1204431Sraj/*
2204431Sraj * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
3204431Sraj *
4204431Sraj *
5204431Sraj * This program is free software; you can redistribute it and/or
6204431Sraj * modify it under the terms of the GNU General Public License as
7204431Sraj * published by the Free Software Foundation; either version 2 of the
8204431Sraj * License, or (at your option) any later version.
9204431Sraj *
10204431Sraj *  This program is distributed in the hope that it will be useful,
11204431Sraj *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12204431Sraj *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13204431Sraj *  General Public License for more details.
14204431Sraj *
15204431Sraj *  You should have received a copy of the GNU General Public License
16204431Sraj *  along with this program; if not, write to the Free Software
17204431Sraj *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
18204431Sraj *                                                                   USA
19204431Sraj */
20204431Sraj
21318102Sgonzo#include <sys/stat.h>
22318102Sgonzo
23204431Sraj#include "dtc.h"
24204431Sraj#include "srcpos.h"
25204431Sraj
26204431Sraj/*
27204431Sraj * Command line options
28204431Sraj */
29204431Srajint quiet;		/* Level of quietness */
30204431Srajint reservenum;		/* Number of memory reservation slots */
31204431Srajint minsize;		/* Minimum blob size */
32204431Srajint padsize;		/* Additional padding to blob */
33318102Sgonzoint alignsize;		/* Additional padding to blob accroding to the alignsize */
34204433Srajint phandle_format = PHANDLE_BOTH;	/* Use linux,phandle or phandle properties */
35318102Sgonzoint generate_symbols;	/* enable symbols & fixup support */
36318102Sgonzoint generate_fixups;		/* suppress generation of fixups on symbol support */
37318102Sgonzoint auto_label_aliases;		/* auto generate labels -> aliases */
38204431Sraj
39318102Sgonzostatic int is_power_of_2(int x)
40318102Sgonzo{
41318102Sgonzo	return (x > 0) && ((x & (x - 1)) == 0);
42318102Sgonzo}
43318102Sgonzo
44204431Srajstatic void fill_fullpaths(struct node *tree, const char *prefix)
45204431Sraj{
46204431Sraj	struct node *child;
47204431Sraj	const char *unit;
48204431Sraj
49204431Sraj	tree->fullpath = join_path(prefix, tree->name);
50204431Sraj
51204431Sraj	unit = strchr(tree->name, '@');
52204431Sraj	if (unit)
53204431Sraj		tree->basenamelen = unit - tree->name;
54204431Sraj	else
55204431Sraj		tree->basenamelen = strlen(tree->name);
56204431Sraj
57204431Sraj	for_each_child(tree, child)
58204431Sraj		fill_fullpaths(child, tree->fullpath);
59204431Sraj}
60204431Sraj
61261215Simp/* Usage related data. */
62318102Sgonzo#define FDT_VERSION(version)	_FDT_VERSION(version)
63318102Sgonzo#define _FDT_VERSION(version)	#version
64261215Simpstatic const char usage_synopsis[] = "dtc [options] <input file>";
65318102Sgonzostatic const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
66261215Simpstatic struct option const usage_long_opts[] = {
67261215Simp	{"quiet",            no_argument, NULL, 'q'},
68261215Simp	{"in-format",         a_argument, NULL, 'I'},
69261215Simp	{"out",               a_argument, NULL, 'o'},
70261215Simp	{"out-format",        a_argument, NULL, 'O'},
71261215Simp	{"out-version",       a_argument, NULL, 'V'},
72261215Simp	{"out-dependency",    a_argument, NULL, 'd'},
73261215Simp	{"reserve",           a_argument, NULL, 'R'},
74261215Simp	{"space",             a_argument, NULL, 'S'},
75261215Simp	{"pad",               a_argument, NULL, 'p'},
76318102Sgonzo	{"align",             a_argument, NULL, 'a'},
77261215Simp	{"boot-cpu",          a_argument, NULL, 'b'},
78261215Simp	{"force",            no_argument, NULL, 'f'},
79261215Simp	{"include",           a_argument, NULL, 'i'},
80261215Simp	{"sort",             no_argument, NULL, 's'},
81261215Simp	{"phandle",           a_argument, NULL, 'H'},
82261215Simp	{"warning",           a_argument, NULL, 'W'},
83261215Simp	{"error",             a_argument, NULL, 'E'},
84318102Sgonzo	{"symbols",	     no_argument, NULL, '@'},
85318102Sgonzo	{"auto-alias",       no_argument, NULL, 'A'},
86261215Simp	{"help",             no_argument, NULL, 'h'},
87261215Simp	{"version",          no_argument, NULL, 'v'},
88261215Simp	{NULL,               no_argument, NULL, 0x0},
89261215Simp};
90261215Simpstatic const char * const usage_opts_help[] = {
91261215Simp	"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
92261215Simp	"\n\tInput formats are:\n"
93261215Simp	 "\t\tdts - device tree source text\n"
94261215Simp	 "\t\tdtb - device tree blob\n"
95261215Simp	 "\t\tfs  - /proc/device-tree style directory",
96261215Simp	"\n\tOutput file",
97261215Simp	"\n\tOutput formats are:\n"
98261215Simp	 "\t\tdts - device tree source text\n"
99261215Simp	 "\t\tdtb - device tree blob\n"
100261215Simp	 "\t\tasm - assembler source",
101318102Sgonzo	"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
102261215Simp	"\n\tOutput dependency file",
103318102Sgonzo	"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
104261215Simp	"\n\tMake the blob at least <bytes> long (extra space)",
105261215Simp	"\n\tAdd padding to the blob of <bytes> long (extra space)",
106318102Sgonzo	"\n\tMake the blob align to the <bytes> (extra space)",
107261215Simp	"\n\tSet the physical boot cpu",
108261215Simp	"\n\tTry to produce output even if the input tree has errors",
109261215Simp	"\n\tAdd a path to search for include files",
110261215Simp	"\n\tSort nodes and properties before outputting (useful for comparing trees)",
111261215Simp	"\n\tValid phandle formats are:\n"
112261215Simp	 "\t\tlegacy - \"linux,phandle\" properties only\n"
113261215Simp	 "\t\tepapr  - \"phandle\" properties only\n"
114261215Simp	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
115261215Simp	"\n\tEnable/disable warnings (prefix with \"no-\")",
116261215Simp	"\n\tEnable/disable errors (prefix with \"no-\")",
117318102Sgonzo	"\n\tEnable generation of symbols",
118318102Sgonzo	"\n\tEnable auto-alias of labels",
119261215Simp	"\n\tPrint this help and exit",
120261215Simp	"\n\tPrint version and exit",
121261215Simp	NULL,
122261215Simp};
123204431Sraj
124318102Sgonzostatic const char *guess_type_by_name(const char *fname, const char *fallback)
125318102Sgonzo{
126318102Sgonzo	const char *s;
127318102Sgonzo
128318102Sgonzo	s = strrchr(fname, '.');
129318102Sgonzo	if (s == NULL)
130318102Sgonzo		return fallback;
131318102Sgonzo	if (!strcasecmp(s, ".dts"))
132318102Sgonzo		return "dts";
133318102Sgonzo	if (!strcasecmp(s, ".dtb"))
134318102Sgonzo		return "dtb";
135318102Sgonzo	return fallback;
136318102Sgonzo}
137318102Sgonzo
138318102Sgonzostatic const char *guess_input_format(const char *fname, const char *fallback)
139318102Sgonzo{
140318102Sgonzo	struct stat statbuf;
141318102Sgonzo	uint32_t magic;
142318102Sgonzo	FILE *f;
143318102Sgonzo
144318102Sgonzo	if (stat(fname, &statbuf) != 0)
145318102Sgonzo		return fallback;
146318102Sgonzo
147318102Sgonzo	if (S_ISDIR(statbuf.st_mode))
148318102Sgonzo		return "fs";
149318102Sgonzo
150318102Sgonzo	if (!S_ISREG(statbuf.st_mode))
151318102Sgonzo		return fallback;
152318102Sgonzo
153318102Sgonzo	f = fopen(fname, "r");
154318102Sgonzo	if (f == NULL)
155318102Sgonzo		return fallback;
156318102Sgonzo	if (fread(&magic, 4, 1, f) != 1) {
157318102Sgonzo		fclose(f);
158318102Sgonzo		return fallback;
159318102Sgonzo	}
160318102Sgonzo	fclose(f);
161318102Sgonzo
162318102Sgonzo	magic = fdt32_to_cpu(magic);
163318102Sgonzo	if (magic == FDT_MAGIC)
164318102Sgonzo		return "dtb";
165318102Sgonzo
166318102Sgonzo	return guess_type_by_name(fname, fallback);
167318102Sgonzo}
168318102Sgonzo
169204431Srajint main(int argc, char *argv[])
170204431Sraj{
171318102Sgonzo	struct dt_info *dti;
172318102Sgonzo	const char *inform = NULL;
173318102Sgonzo	const char *outform = NULL;
174204431Sraj	const char *outname = "-";
175238742Simp	const char *depname = NULL;
176261215Simp	bool force = false, sort = false;
177204431Sraj	const char *arg;
178204431Sraj	int opt;
179204431Sraj	FILE *outf = NULL;
180204431Sraj	int outversion = DEFAULT_FDT_VERSION;
181204431Sraj	long long cmdline_boot_cpuid = -1;
182204431Sraj
183204431Sraj	quiet      = 0;
184204431Sraj	reservenum = 0;
185204431Sraj	minsize    = 0;
186204431Sraj	padsize    = 0;
187318102Sgonzo	alignsize  = 0;
188204431Sraj
189261215Simp	while ((opt = util_getopt_long()) != EOF) {
190204431Sraj		switch (opt) {
191204431Sraj		case 'I':
192204431Sraj			inform = optarg;
193204431Sraj			break;
194204431Sraj		case 'O':
195204431Sraj			outform = optarg;
196204431Sraj			break;
197204431Sraj		case 'o':
198204431Sraj			outname = optarg;
199204431Sraj			break;
200204431Sraj		case 'V':
201204431Sraj			outversion = strtol(optarg, NULL, 0);
202204431Sraj			break;
203238742Simp		case 'd':
204238742Simp			depname = optarg;
205238742Simp			break;
206204431Sraj		case 'R':
207204431Sraj			reservenum = strtol(optarg, NULL, 0);
208204431Sraj			break;
209204431Sraj		case 'S':
210204431Sraj			minsize = strtol(optarg, NULL, 0);
211204431Sraj			break;
212204431Sraj		case 'p':
213204431Sraj			padsize = strtol(optarg, NULL, 0);
214204431Sraj			break;
215318102Sgonzo		case 'a':
216318102Sgonzo			alignsize = strtol(optarg, NULL, 0);
217318102Sgonzo			if (!is_power_of_2(alignsize))
218318102Sgonzo				die("Invalid argument \"%d\" to -a option\n",
219318102Sgonzo				    alignsize);
220318102Sgonzo			break;
221204431Sraj		case 'f':
222261215Simp			force = true;
223204431Sraj			break;
224204431Sraj		case 'q':
225204431Sraj			quiet++;
226204431Sraj			break;
227204431Sraj		case 'b':
228204431Sraj			cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
229204431Sraj			break;
230238742Simp		case 'i':
231238742Simp			srcfile_add_search_path(optarg);
232238742Simp			break;
233204431Sraj		case 'v':
234261215Simp			util_version();
235204433Sraj		case 'H':
236204433Sraj			if (streq(optarg, "legacy"))
237204433Sraj				phandle_format = PHANDLE_LEGACY;
238204433Sraj			else if (streq(optarg, "epapr"))
239204433Sraj				phandle_format = PHANDLE_EPAPR;
240204433Sraj			else if (streq(optarg, "both"))
241204433Sraj				phandle_format = PHANDLE_BOTH;
242204433Sraj			else
243204433Sraj				die("Invalid argument \"%s\" to -H option\n",
244204433Sraj				    optarg);
245204433Sraj			break;
246204433Sraj
247238742Simp		case 's':
248261215Simp			sort = true;
249238742Simp			break;
250238742Simp
251238742Simp		case 'W':
252238742Simp			parse_checks_option(true, false, optarg);
253238742Simp			break;
254238742Simp
255238742Simp		case 'E':
256238742Simp			parse_checks_option(false, true, optarg);
257238742Simp			break;
258238742Simp
259318102Sgonzo		case '@':
260318102Sgonzo			generate_symbols = 1;
261318102Sgonzo			break;
262318102Sgonzo		case 'A':
263318102Sgonzo			auto_label_aliases = 1;
264318102Sgonzo			break;
265318102Sgonzo
266204431Sraj		case 'h':
267261215Simp			usage(NULL);
268204431Sraj		default:
269261215Simp			usage("unknown option");
270204431Sraj		}
271204431Sraj	}
272204431Sraj
273204431Sraj	if (argc > (optind+1))
274261215Simp		usage("missing files");
275204431Sraj	else if (argc < (optind+1))
276204431Sraj		arg = "-";
277204431Sraj	else
278204431Sraj		arg = argv[optind];
279204431Sraj
280204431Sraj	/* minsize and padsize are mutually exclusive */
281204431Sraj	if (minsize && padsize)
282204431Sraj		die("Can't set both -p and -S\n");
283204431Sraj
284238742Simp	if (depname) {
285238742Simp		depfile = fopen(depname, "w");
286238742Simp		if (!depfile)
287238742Simp			die("Couldn't open dependency file %s: %s\n", depname,
288238742Simp			    strerror(errno));
289238742Simp		fprintf(depfile, "%s:", outname);
290238742Simp	}
291204431Sraj
292318102Sgonzo	if (inform == NULL)
293318102Sgonzo		inform = guess_input_format(arg, "dts");
294318102Sgonzo	if (outform == NULL) {
295318102Sgonzo		outform = guess_type_by_name(outname, NULL);
296318102Sgonzo		if (outform == NULL) {
297318102Sgonzo			if (streq(inform, "dts"))
298318102Sgonzo				outform = "dtb";
299318102Sgonzo			else
300318102Sgonzo				outform = "dts";
301318102Sgonzo		}
302318102Sgonzo	}
303204431Sraj	if (streq(inform, "dts"))
304318102Sgonzo		dti = dt_from_source(arg);
305204431Sraj	else if (streq(inform, "fs"))
306318102Sgonzo		dti = dt_from_fs(arg);
307204431Sraj	else if(streq(inform, "dtb"))
308318102Sgonzo		dti = dt_from_blob(arg);
309204431Sraj	else
310204431Sraj		die("Unknown input format \"%s\"\n", inform);
311204431Sraj
312318102Sgonzo	dti->outname = outname;
313318102Sgonzo
314238742Simp	if (depfile) {
315238742Simp		fputc('\n', depfile);
316238742Simp		fclose(depfile);
317238742Simp	}
318238742Simp
319204431Sraj	if (cmdline_boot_cpuid != -1)
320318102Sgonzo		dti->boot_cpuid_phys = cmdline_boot_cpuid;
321204431Sraj
322318102Sgonzo	fill_fullpaths(dti->dt, "");
323318102Sgonzo	process_checks(force, dti);
324204431Sraj
325318102Sgonzo	/* on a plugin, generate by default */
326318102Sgonzo	if (dti->dtsflags & DTSF_PLUGIN) {
327318102Sgonzo		generate_fixups = 1;
328318102Sgonzo	}
329318102Sgonzo
330318102Sgonzo	if (auto_label_aliases)
331318102Sgonzo		generate_label_tree(dti, "aliases", false);
332318102Sgonzo
333318102Sgonzo	if (generate_symbols)
334318102Sgonzo		generate_label_tree(dti, "__symbols__", true);
335318102Sgonzo
336318102Sgonzo	if (generate_fixups) {
337318102Sgonzo		generate_fixups_tree(dti, "__fixups__");
338318102Sgonzo		generate_local_fixups_tree(dti, "__local_fixups__");
339318102Sgonzo	}
340318102Sgonzo
341238742Simp	if (sort)
342318102Sgonzo		sort_tree(dti);
343204431Sraj
344204431Sraj	if (streq(outname, "-")) {
345204431Sraj		outf = stdout;
346204431Sraj	} else {
347318102Sgonzo		outf = fopen(outname, "wb");
348204431Sraj		if (! outf)
349204431Sraj			die("Couldn't open output file %s: %s\n",
350204431Sraj			    outname, strerror(errno));
351204431Sraj	}
352204431Sraj
353204431Sraj	if (streq(outform, "dts")) {
354318102Sgonzo		dt_to_source(outf, dti);
355204431Sraj	} else if (streq(outform, "dtb")) {
356318102Sgonzo		dt_to_blob(outf, dti, outversion);
357204431Sraj	} else if (streq(outform, "asm")) {
358318102Sgonzo		dt_to_asm(outf, dti, outversion);
359204431Sraj	} else if (streq(outform, "null")) {
360204431Sraj		/* do nothing */
361204431Sraj	} else {
362204431Sraj		die("Unknown output format \"%s\"\n", outform);
363204431Sraj	}
364204431Sraj
365204431Sraj	exit(0);
366204431Sraj}
367