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