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