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