0001
0002
0003
0004
0005
0006 #include <sys/stat.h>
0007
0008 #include "dtc.h"
0009 #include "srcpos.h"
0010
0011
0012
0013
0014 int quiet;
0015 unsigned int reservenum;
0016 int minsize;
0017 int padsize;
0018 int alignsize;
0019 int phandle_format = PHANDLE_EPAPR;
0020 int generate_symbols;
0021 int generate_fixups;
0022 int auto_label_aliases;
0023 int annotate;
0024
0025
0026 static int is_power_of_2(int x)
0027 {
0028 return (x > 0) && ((x & (x - 1)) == 0);
0029 }
0030
0031 static void fill_fullpaths(struct node *tree, const char *prefix)
0032 {
0033 struct node *child;
0034 const char *unit;
0035
0036 tree->fullpath = join_path(prefix, tree->name);
0037
0038 unit = strchr(tree->name, '@');
0039 if (unit)
0040 tree->basenamelen = unit - tree->name;
0041 else
0042 tree->basenamelen = strlen(tree->name);
0043
0044 for_each_child(tree, child)
0045 fill_fullpaths(child, tree->fullpath);
0046 }
0047
0048
0049 static const char usage_synopsis[] = "dtc [options] <input file>";
0050 static const char usage_short_opts[] = "qI:O:o:V:d:R:S:p:a:fb:i:H:sW:E:@AThv";
0051 static struct option const usage_long_opts[] = {
0052 {"quiet", no_argument, NULL, 'q'},
0053 {"in-format", a_argument, NULL, 'I'},
0054 {"out", a_argument, NULL, 'o'},
0055 {"out-format", a_argument, NULL, 'O'},
0056 {"out-version", a_argument, NULL, 'V'},
0057 {"out-dependency", a_argument, NULL, 'd'},
0058 {"reserve", a_argument, NULL, 'R'},
0059 {"space", a_argument, NULL, 'S'},
0060 {"pad", a_argument, NULL, 'p'},
0061 {"align", a_argument, NULL, 'a'},
0062 {"boot-cpu", a_argument, NULL, 'b'},
0063 {"force", no_argument, NULL, 'f'},
0064 {"include", a_argument, NULL, 'i'},
0065 {"sort", no_argument, NULL, 's'},
0066 {"phandle", a_argument, NULL, 'H'},
0067 {"warning", a_argument, NULL, 'W'},
0068 {"error", a_argument, NULL, 'E'},
0069 {"symbols", no_argument, NULL, '@'},
0070 {"auto-alias", no_argument, NULL, 'A'},
0071 {"annotate", no_argument, NULL, 'T'},
0072 {"help", no_argument, NULL, 'h'},
0073 {"version", no_argument, NULL, 'v'},
0074 {NULL, no_argument, NULL, 0x0},
0075 };
0076 static const char * const usage_opts_help[] = {
0077 "\n\tQuiet: -q suppress warnings, -qq errors, -qqq all",
0078 "\n\tInput formats are:\n"
0079 "\t\tdts - device tree source text\n"
0080 "\t\tdtb - device tree blob\n"
0081 "\t\tfs - /proc/device-tree style directory",
0082 "\n\tOutput file",
0083 "\n\tOutput formats are:\n"
0084 "\t\tdts - device tree source text\n"
0085 "\t\tdtb - device tree blob\n"
0086 #ifndef NO_YAML
0087 "\t\tyaml - device tree encoded as YAML\n"
0088 #endif
0089 "\t\tasm - assembler source",
0090 "\n\tBlob version to produce, defaults to "stringify(DEFAULT_FDT_VERSION)" (for dtb and asm output)",
0091 "\n\tOutput dependency file",
0092 "\n\tMake space for <number> reserve map entries (for dtb and asm output)",
0093 "\n\tMake the blob at least <bytes> long (extra space)",
0094 "\n\tAdd padding to the blob of <bytes> long (extra space)",
0095 "\n\tMake the blob align to the <bytes> (extra space)",
0096 "\n\tSet the physical boot cpu",
0097 "\n\tTry to produce output even if the input tree has errors",
0098 "\n\tAdd a path to search for include files",
0099 "\n\tSort nodes and properties before outputting (useful for comparing trees)",
0100 "\n\tValid phandle formats are:\n"
0101 "\t\tlegacy - \"linux,phandle\" properties only\n"
0102 "\t\tepapr - \"phandle\" properties only\n"
0103 "\t\tboth - Both \"linux,phandle\" and \"phandle\" properties",
0104 "\n\tEnable/disable warnings (prefix with \"no-\")",
0105 "\n\tEnable/disable errors (prefix with \"no-\")",
0106 "\n\tEnable generation of symbols",
0107 "\n\tEnable auto-alias of labels",
0108 "\n\tAnnotate output .dts with input source file and line (-T -T for more details)",
0109 "\n\tPrint this help and exit",
0110 "\n\tPrint version and exit",
0111 NULL,
0112 };
0113
0114 static const char *guess_type_by_name(const char *fname, const char *fallback)
0115 {
0116 const char *s;
0117
0118 s = strrchr(fname, '.');
0119 if (s == NULL)
0120 return fallback;
0121 if (!strcasecmp(s, ".dts"))
0122 return "dts";
0123 if (!strcasecmp(s, ".yaml"))
0124 return "yaml";
0125 if (!strcasecmp(s, ".dtbo"))
0126 return "dtb";
0127 if (!strcasecmp(s, ".dtb"))
0128 return "dtb";
0129 return fallback;
0130 }
0131
0132 static const char *guess_input_format(const char *fname, const char *fallback)
0133 {
0134 struct stat statbuf;
0135 fdt32_t magic;
0136 FILE *f;
0137
0138 if (stat(fname, &statbuf) != 0)
0139 return fallback;
0140
0141 if (S_ISDIR(statbuf.st_mode))
0142 return "fs";
0143
0144 if (!S_ISREG(statbuf.st_mode))
0145 return fallback;
0146
0147 f = fopen(fname, "r");
0148 if (f == NULL)
0149 return fallback;
0150 if (fread(&magic, 4, 1, f) != 1) {
0151 fclose(f);
0152 return fallback;
0153 }
0154 fclose(f);
0155
0156 if (fdt32_to_cpu(magic) == FDT_MAGIC)
0157 return "dtb";
0158
0159 return guess_type_by_name(fname, fallback);
0160 }
0161
0162 int main(int argc, char *argv[])
0163 {
0164 struct dt_info *dti;
0165 const char *inform = NULL;
0166 const char *outform = NULL;
0167 const char *outname = "-";
0168 const char *depname = NULL;
0169 bool force = false, sort = false;
0170 const char *arg;
0171 int opt;
0172 FILE *outf = NULL;
0173 int outversion = DEFAULT_FDT_VERSION;
0174 long long cmdline_boot_cpuid = -1;
0175
0176 quiet = 0;
0177 reservenum = 0;
0178 minsize = 0;
0179 padsize = 0;
0180 alignsize = 0;
0181
0182 while ((opt = util_getopt_long()) != EOF) {
0183 switch (opt) {
0184 case 'I':
0185 inform = optarg;
0186 break;
0187 case 'O':
0188 outform = optarg;
0189 break;
0190 case 'o':
0191 outname = optarg;
0192 break;
0193 case 'V':
0194 outversion = strtol(optarg, NULL, 0);
0195 break;
0196 case 'd':
0197 depname = optarg;
0198 break;
0199 case 'R':
0200 reservenum = strtoul(optarg, NULL, 0);
0201 break;
0202 case 'S':
0203 minsize = strtol(optarg, NULL, 0);
0204 break;
0205 case 'p':
0206 padsize = strtol(optarg, NULL, 0);
0207 break;
0208 case 'a':
0209 alignsize = strtol(optarg, NULL, 0);
0210 if (!is_power_of_2(alignsize))
0211 die("Invalid argument \"%d\" to -a option\n",
0212 alignsize);
0213 break;
0214 case 'f':
0215 force = true;
0216 break;
0217 case 'q':
0218 quiet++;
0219 break;
0220 case 'b':
0221 cmdline_boot_cpuid = strtoll(optarg, NULL, 0);
0222 break;
0223 case 'i':
0224 srcfile_add_search_path(optarg);
0225 break;
0226 case 'v':
0227 util_version();
0228 case 'H':
0229 if (streq(optarg, "legacy"))
0230 phandle_format = PHANDLE_LEGACY;
0231 else if (streq(optarg, "epapr"))
0232 phandle_format = PHANDLE_EPAPR;
0233 else if (streq(optarg, "both"))
0234 phandle_format = PHANDLE_BOTH;
0235 else
0236 die("Invalid argument \"%s\" to -H option\n",
0237 optarg);
0238 break;
0239
0240 case 's':
0241 sort = true;
0242 break;
0243
0244 case 'W':
0245 parse_checks_option(true, false, optarg);
0246 break;
0247
0248 case 'E':
0249 parse_checks_option(false, true, optarg);
0250 break;
0251
0252 case '@':
0253 generate_symbols = 1;
0254 break;
0255 case 'A':
0256 auto_label_aliases = 1;
0257 break;
0258 case 'T':
0259 annotate++;
0260 break;
0261
0262 case 'h':
0263 usage(NULL);
0264 default:
0265 usage("unknown option");
0266 }
0267 }
0268
0269 if (argc > (optind+1))
0270 usage("missing files");
0271 else if (argc < (optind+1))
0272 arg = "-";
0273 else
0274 arg = argv[optind];
0275
0276
0277 if (minsize && padsize)
0278 die("Can't set both -p and -S\n");
0279
0280 if (depname) {
0281 depfile = fopen(depname, "w");
0282 if (!depfile)
0283 die("Couldn't open dependency file %s: %s\n", depname,
0284 strerror(errno));
0285 fprintf(depfile, "%s:", outname);
0286 }
0287
0288 if (inform == NULL)
0289 inform = guess_input_format(arg, "dts");
0290 if (outform == NULL) {
0291 outform = guess_type_by_name(outname, NULL);
0292 if (outform == NULL) {
0293 if (streq(inform, "dts"))
0294 outform = "dtb";
0295 else
0296 outform = "dts";
0297 }
0298 }
0299 if (annotate && (!streq(inform, "dts") || !streq(outform, "dts")))
0300 die("--annotate requires -I dts -O dts\n");
0301 if (streq(inform, "dts"))
0302 dti = dt_from_source(arg);
0303 else if (streq(inform, "fs"))
0304 dti = dt_from_fs(arg);
0305 else if(streq(inform, "dtb"))
0306 dti = dt_from_blob(arg);
0307 else
0308 die("Unknown input format \"%s\"\n", inform);
0309
0310 dti->outname = outname;
0311
0312 if (depfile) {
0313 fputc('\n', depfile);
0314 fclose(depfile);
0315 }
0316
0317 if (cmdline_boot_cpuid != -1)
0318 dti->boot_cpuid_phys = cmdline_boot_cpuid;
0319
0320 fill_fullpaths(dti->dt, "");
0321
0322
0323 if (dti->dtsflags & DTSF_PLUGIN) {
0324 generate_fixups = 1;
0325 }
0326
0327 process_checks(force, dti);
0328
0329 if (auto_label_aliases)
0330 generate_label_tree(dti, "aliases", false);
0331
0332 if (generate_symbols)
0333 generate_label_tree(dti, "__symbols__", true);
0334
0335 if (generate_fixups) {
0336 generate_fixups_tree(dti, "__fixups__");
0337 generate_local_fixups_tree(dti, "__local_fixups__");
0338 }
0339
0340 if (sort)
0341 sort_tree(dti);
0342
0343 if (streq(outname, "-")) {
0344 outf = stdout;
0345 } else {
0346 outf = fopen(outname, "wb");
0347 if (! outf)
0348 die("Couldn't open output file %s: %s\n",
0349 outname, strerror(errno));
0350 }
0351
0352 if (streq(outform, "dts")) {
0353 dt_to_source(outf, dti);
0354 #ifndef NO_YAML
0355 } else if (streq(outform, "yaml")) {
0356 if (!streq(inform, "dts"))
0357 die("YAML output format requires dts input format\n");
0358 dt_to_yaml(outf, dti);
0359 #endif
0360 } else if (streq(outform, "dtb")) {
0361 dt_to_blob(outf, dti, outversion);
0362 } else if (streq(outform, "asm")) {
0363 dt_to_asm(outf, dti, outversion);
0364 } else if (streq(outform, "null")) {
0365
0366 } else {
0367 die("Unknown output format \"%s\"\n", outform);
0368 }
0369
0370 exit(0);
0371 }