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