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