dtc.c 9.3 KB
Newer Older
D
David Gibson 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 * (C) Copyright David Gibson <dwg@au1.ibm.com>, IBM Corporation.  2005.
 *
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 *  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.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
 *                                                                   USA
 */

21 22
#include <sys/stat.h>

D
David Gibson 已提交
23 24 25 26 27 28 29 30 31 32
#include "dtc.h"
#include "srcpos.h"

/*
 * Command line options
 */
int quiet;		/* Level of quietness */
int reservenum;		/* Number of memory reservation slots */
int minsize;		/* Minimum blob size */
int padsize;		/* Additional padding to blob */
33
int alignsize;		/* Additional padding to blob accroding to the alignsize */
34
int phandle_format = PHANDLE_EPAPR;	/* Use linux,phandle or phandle properties */
35 36 37 38 39 40 41 42
int generate_symbols;	/* enable symbols & fixup support */
int generate_fixups;		/* suppress generation of fixups on symbol support */
int auto_label_aliases;		/* auto generate labels -> aliases */

static int is_power_of_2(int x)
{
	return (x > 0) && ((x & (x - 1)) == 0);
}
D
David Gibson 已提交
43

44
static void fill_fullpaths(struct node *tree, const char *prefix)
D
David Gibson 已提交
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
{
	struct node *child;
	const char *unit;

	tree->fullpath = join_path(prefix, tree->name);

	unit = strchr(tree->name, '@');
	if (unit)
		tree->basenamelen = unit - tree->name;
	else
		tree->basenamelen = strlen(tree->name);

	for_each_child(tree, child)
		fill_fullpaths(child, tree->fullpath);
}

61
/* Usage related data. */
62 63
#define FDT_VERSION(version)	_FDT_VERSION(version)
#define _FDT_VERSION(version)	#version
64
static const char usage_synopsis[] = "dtc [options] <input file>";
65
static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@Ahv";
66 67 68 69 70 71 72 73 74 75
static struct option const usage_long_opts[] = {
	{"quiet",            no_argument, NULL, 'q'},
	{"in-format",         a_argument, NULL, 'I'},
	{"out",               a_argument, NULL, 'o'},
	{"out-format",        a_argument, NULL, 'O'},
	{"out-version",       a_argument, NULL, 'V'},
	{"out-dependency",    a_argument, NULL, 'd'},
	{"reserve",           a_argument, NULL, 'R'},
	{"space",             a_argument, NULL, 'S'},
	{"pad",               a_argument, NULL, 'p'},
76
	{"align",             a_argument, NULL, 'a'},
77 78 79 80 81 82 83
	{"boot-cpu",          a_argument, NULL, 'b'},
	{"force",            no_argument, NULL, 'f'},
	{"include",           a_argument, NULL, 'i'},
	{"sort",             no_argument, NULL, 's'},
	{"phandle",           a_argument, NULL, 'H'},
	{"warning",           a_argument, NULL, 'W'},
	{"error",             a_argument, NULL, 'E'},
84 85
	{"symbols",	     no_argument, NULL, '@'},
	{"auto-alias",       no_argument, NULL, 'A'},
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
	{"help",             no_argument, NULL, 'h'},
	{"version",          no_argument, NULL, 'v'},
	{NULL,               no_argument, NULL, 0x0},
};
static const char * const usage_opts_help[] = {
	"\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
	"\n\tInput formats are:\n"
	 "\t\tdts - device tree source text\n"
	 "\t\tdtb - device tree blob\n"
	 "\t\tfs  - /proc/device-tree style directory",
	"\n\tOutput file",
	"\n\tOutput formats are:\n"
	 "\t\tdts - device tree source text\n"
	 "\t\tdtb - device tree blob\n"
	 "\t\tasm - assembler source",
101
	"\n\tBlob version to produce, defaults to "FDT_VERSION(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
102
	"\n\tOutput dependency file",
103
	"\n\tMake space for <number> reserve map entries (for dtb and asm output)",
104 105
	"\n\tMake the blob at least <bytes> long (extra space)",
	"\n\tAdd padding to the blob of <bytes> long (extra space)",
106
	"\n\tMake the blob align to the <bytes> (extra space)",
107 108 109 110 111 112 113 114 115 116
	"\n\tSet the physical boot cpu",
	"\n\tTry to produce output even if the input tree has errors",
	"\n\tAdd a path to search for include files",
	"\n\tSort nodes and properties before outputting (useful for comparing trees)",
	"\n\tValid phandle formats are:\n"
	 "\t\tlegacy - \"linux,phandle\" properties only\n"
	 "\t\tepapr  - \"phandle\" properties only\n"
	 "\t\tboth   - Both \"linux,phandle\" and \"phandle\" properties",
	"\n\tEnable/disable warnings (prefix with \"no-\")",
	"\n\tEnable/disable errors (prefix with \"no-\")",
117 118
	"\n\tEnable generation of symbols",
	"\n\tEnable auto-alias of labels",
119 120 121 122
	"\n\tPrint this help and exit",
	"\n\tPrint version and exit",
	NULL,
};
D
David Gibson 已提交
123

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140
static const char *guess_type_by_name(const char *fname, const char *fallback)
{
	const char *s;

	s = strrchr(fname, '.');
	if (s == NULL)
		return fallback;
	if (!strcasecmp(s, ".dts"))
		return "dts";
	if (!strcasecmp(s, ".dtb"))
		return "dtb";
	return fallback;
}

static const char *guess_input_format(const char *fname, const char *fallback)
{
	struct stat statbuf;
141
	fdt32_t magic;
142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
	FILE *f;

	if (stat(fname, &statbuf) != 0)
		return fallback;

	if (S_ISDIR(statbuf.st_mode))
		return "fs";

	if (!S_ISREG(statbuf.st_mode))
		return fallback;

	f = fopen(fname, "r");
	if (f == NULL)
		return fallback;
	if (fread(&magic, 4, 1, f) != 1) {
		fclose(f);
		return fallback;
	}
	fclose(f);

162
	if (fdt32_to_cpu(magic) == FDT_MAGIC)
163 164 165 166 167
		return "dtb";

	return guess_type_by_name(fname, fallback);
}

D
David Gibson 已提交
168 169
int main(int argc, char *argv[])
{
170
	struct dt_info *dti;
171 172
	const char *inform = NULL;
	const char *outform = NULL;
D
David Gibson 已提交
173
	const char *outname = "-";
174
	const char *depname = NULL;
175
	bool force = false, sort = false;
D
David Gibson 已提交
176 177 178 179
	const char *arg;
	int opt;
	FILE *outf = NULL;
	int outversion = DEFAULT_FDT_VERSION;
180
	long long cmdline_boot_cpuid = -1;
D
David Gibson 已提交
181 182 183 184 185

	quiet      = 0;
	reservenum = 0;
	minsize    = 0;
	padsize    = 0;
186
	alignsize  = 0;
D
David Gibson 已提交
187

188
	while ((opt = util_getopt_long()) != EOF) {
D
David Gibson 已提交
189 190 191 192 193 194 195 196 197 198 199 200 201
		switch (opt) {
		case 'I':
			inform = optarg;
			break;
		case 'O':
			outform = optarg;
			break;
		case 'o':
			outname = optarg;
			break;
		case 'V':
			outversion = strtol(optarg, NULL, 0);
			break;
202 203 204
		case 'd':
			depname = optarg;
			break;
D
David Gibson 已提交
205 206 207 208 209 210 211 212 213
		case 'R':
			reservenum = strtol(optarg, NULL, 0);
			break;
		case 'S':
			minsize = strtol(optarg, NULL, 0);
			break;
		case 'p':
			padsize = strtol(optarg, NULL, 0);
			break;
214 215 216 217
		case 'a':
			alignsize = strtol(optarg, NULL, 0);
			if (!is_power_of_2(alignsize))
				die("Invalid argument \"%d\" to -a option\n",
218
				    alignsize);
219
			break;
D
David Gibson 已提交
220
		case 'f':
221
			force = true;
D
David Gibson 已提交
222 223 224 225 226
			break;
		case 'q':
			quiet++;
			break;
		case 'b':
227
			cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
D
David Gibson 已提交
228
			break;
S
Stephen Warren 已提交
229 230 231
		case 'i':
			srcfile_add_search_path(optarg);
			break;
D
David Gibson 已提交
232
		case 'v':
233
			util_version();
234 235 236 237 238 239 240 241 242 243 244 245 246
		case 'H':
			if (streq(optarg, "legacy"))
				phandle_format = PHANDLE_LEGACY;
			else if (streq(optarg, "epapr"))
				phandle_format = PHANDLE_EPAPR;
			else if (streq(optarg, "both"))
				phandle_format = PHANDLE_BOTH;
			else
				die("Invalid argument \"%s\" to -H option\n",
				    optarg);
			break;

		case 's':
247
			sort = true;
248 249
			break;

S
Stephen Warren 已提交
250 251 252 253 254 255 256 257
		case 'W':
			parse_checks_option(true, false, optarg);
			break;

		case 'E':
			parse_checks_option(false, true, optarg);
			break;

258 259 260 261 262 263 264
		case '@':
			generate_symbols = 1;
			break;
		case 'A':
			auto_label_aliases = 1;
			break;

D
David Gibson 已提交
265
		case 'h':
266
			usage(NULL);
D
David Gibson 已提交
267
		default:
268
			usage("unknown option");
D
David Gibson 已提交
269 270 271 272
		}
	}

	if (argc > (optind+1))
273
		usage("missing files");
D
David Gibson 已提交
274 275 276 277 278 279
	else if (argc < (optind+1))
		arg = "-";
	else
		arg = argv[optind];

	/* minsize and padsize are mutually exclusive */
280
	if (minsize && padsize)
D
David Gibson 已提交
281 282
		die("Can't set both -p and -S\n");

283 284 285 286 287 288 289 290
	if (depname) {
		depfile = fopen(depname, "w");
		if (!depfile)
			die("Couldn't open dependency file %s: %s\n", depname,
			    strerror(errno));
		fprintf(depfile, "%s:", outname);
	}

291 292 293 294 295 296 297 298 299 300 301
	if (inform == NULL)
		inform = guess_input_format(arg, "dts");
	if (outform == NULL) {
		outform = guess_type_by_name(outname, NULL);
		if (outform == NULL) {
			if (streq(inform, "dts"))
				outform = "dtb";
			else
				outform = "dts";
		}
	}
302
	if (streq(inform, "dts"))
303
		dti = dt_from_source(arg);
304
	else if (streq(inform, "fs"))
305
		dti = dt_from_fs(arg);
306
	else if(streq(inform, "dtb"))
307
		dti = dt_from_blob(arg);
308
	else
D
David Gibson 已提交
309 310
		die("Unknown input format \"%s\"\n", inform);

311 312
	dti->outname = outname;

313 314 315 316 317
	if (depfile) {
		fputc('\n', depfile);
		fclose(depfile);
	}

318
	if (cmdline_boot_cpuid != -1)
319 320 321 322 323 324 325 326 327
		dti->boot_cpuid_phys = cmdline_boot_cpuid;

	fill_fullpaths(dti->dt, "");
	process_checks(force, dti);

	/* on a plugin, generate by default */
	if (dti->dtsflags & DTSF_PLUGIN) {
		generate_fixups = 1;
	}
D
David Gibson 已提交
328

329 330 331 332 333 334 335 336 337 338
	if (auto_label_aliases)
		generate_label_tree(dti, "aliases", false);

	if (generate_symbols)
		generate_label_tree(dti, "__symbols__", true);

	if (generate_fixups) {
		generate_fixups_tree(dti, "__fixups__");
		generate_local_fixups_tree(dti, "__local_fixups__");
	}
D
David Gibson 已提交
339

340
	if (sort)
341
		sort_tree(dti);
D
David Gibson 已提交
342 343 344 345

	if (streq(outname, "-")) {
		outf = stdout;
	} else {
346
		outf = fopen(outname, "wb");
D
David Gibson 已提交
347 348 349 350 351 352
		if (! outf)
			die("Couldn't open output file %s: %s\n",
			    outname, strerror(errno));
	}

	if (streq(outform, "dts")) {
353
		dt_to_source(outf, dti);
D
David Gibson 已提交
354
	} else if (streq(outform, "dtb")) {
355
		dt_to_blob(outf, dti, outversion);
D
David Gibson 已提交
356
	} else if (streq(outform, "asm")) {
357
		dt_to_asm(outf, dti, outversion);
D
David Gibson 已提交
358 359 360 361 362 363 364 365
	} else if (streq(outform, "null")) {
		/* do nothing */
	} else {
		die("Unknown output format \"%s\"\n", outform);
	}

	exit(0);
}