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