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