1245803Stheraven/*- 2245803Stheraven * Copyright (c) 2013 David Chisnall 3245803Stheraven * All rights reserved. 4245803Stheraven * 5245803Stheraven * This software was developed by SRI International and the University of 6245803Stheraven * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237) 7245803Stheraven * ("CTSRD"), as part of the DARPA CRASH research programme. 8245803Stheraven * 9245803Stheraven * Redistribution and use in source and binary forms, with or without 10245803Stheraven * modification, are permitted provided that the following conditions 11245803Stheraven * are met: 12245803Stheraven * 1. Redistributions of source code must retain the above copyright 13245803Stheraven * notice, this list of conditions and the following disclaimer. 14245803Stheraven * 2. Redistributions in binary form must reproduce the above copyright 15245803Stheraven * notice, this list of conditions and the following disclaimer in the 16245803Stheraven * documentation and/or other materials provided with the distribution. 17245803Stheraven * 18245803Stheraven * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19245803Stheraven * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20245803Stheraven * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21245803Stheraven * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22245803Stheraven * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23245803Stheraven * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24245803Stheraven * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25245803Stheraven * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26245803Stheraven * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27245803Stheraven * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28245803Stheraven * SUCH DAMAGE. 29245803Stheraven * 30245803Stheraven * $FreeBSD$ 31245803Stheraven */ 32245803Stheraven 33245803Stheraven#include <sys/resource.h> 34245803Stheraven#include <fcntl.h> 35245803Stheraven#include <libgen.h> 36245839Stheraven#include <limits.h> 37245839Stheraven#include <stdio.h> 38245839Stheraven#include <stdlib.h> 39245839Stheraven#include <time.h> 40245839Stheraven#include <unistd.h> 41245803Stheraven 42245839Stheraven 43245803Stheraven#include "fdt.hh" 44245803Stheraven#include "checking.hh" 45245803Stheraven 46245803Stheravenusing namespace dtc; 47245803Stheraven 48245803Stheraven/** 49245803Stheraven * The current major version of the tool. 50245803Stheraven */ 51245803Stheravenint version_major = 0; 52245803Stheraven/** 53245803Stheraven * The current minor version of the tool. 54245803Stheraven */ 55245803Stheravenint version_minor = 4; 56245803Stheraven/** 57245803Stheraven * The current patch level of the tool. 58245803Stheraven */ 59245803Stheravenint version_patch = 0; 60245803Stheraven 61245803Stheravenstatic void usage(const char* argv0) 62245803Stheraven{ 63245803Stheraven fprintf(stderr, "Usage:\n" 64245803Stheraven "\t%s\t[-fhsv] [-b boot_cpu_id] [-d dependency_file]" 65245803Stheraven "[-E [no-]checker_name]\n" 66245803Stheraven "\t\t[-H phandle_format] [-I input_format]" 67245803Stheraven "[-O output_format]\n" 68245803Stheraven "\t\t[-o output_file] [-R entries] [-S bytes] [-p bytes]" 69245803Stheraven "[-V blob_version]\n" 70245803Stheraven "\t\t-W [no-]checker_name] input_file\n", basename(argv0)); 71245803Stheraven} 72245803Stheraven 73245803Stheraven/** 74245803Stheraven * Prints the current version of this program.. 75245803Stheraven */ 76245803Stheravenstatic void version(const char* progname) 77245803Stheraven{ 78245803Stheraven fprintf(stderr, "Version: %s %d.%d.%d\n", progname, version_major, 79245803Stheraven version_minor, version_patch); 80245803Stheraven} 81245803Stheraven 82245803Stheravenusing fdt::device_tree; 83245803Stheraven 84245803Stheravenint 85245803Stheravenmain(int argc, char **argv) 86245803Stheraven{ 87245803Stheraven int ch; 88245803Stheraven int outfile = fileno(stdout); 89245803Stheraven const char *outfile_name = "-"; 90245803Stheraven const char *in_file = "-"; 91245803Stheraven FILE *depfile = 0; 92245803Stheraven bool debug_mode = false; 93245803Stheraven void (device_tree::*write_fn)(int) = &device_tree::write_binary; 94245803Stheraven void (device_tree::*read_fn)(const char*, FILE*) = 95245803Stheraven &device_tree::parse_dts; 96245803Stheraven uint32_t boot_cpu; 97245803Stheraven bool boot_cpu_specified = false; 98245803Stheraven bool keep_going = false; 99245803Stheraven bool sort = false; 100245803Stheraven clock_t c0 = clock(); 101245803Stheraven class device_tree tree; 102245803Stheraven fdt::checking::check_manager checks; 103254522Stheraven const char *options = "hqI:O:o:V:d:R:S:p:b:fisvH:W:E:DP:"; 104245803Stheraven 105245803Stheraven // Don't forget to update the man page if any more options are added. 106245803Stheraven while ((ch = getopt(argc, argv, options)) != -1) 107245803Stheraven { 108245803Stheraven switch (ch) 109245803Stheraven { 110245803Stheraven case 'h': 111245803Stheraven usage(argv[0]); 112245803Stheraven return EXIT_SUCCESS; 113245803Stheraven case 'v': 114245803Stheraven version(argv[0]); 115245803Stheraven return EXIT_SUCCESS; 116245803Stheraven case 'I': 117245803Stheraven { 118245803Stheraven string arg = string(optarg); 119245803Stheraven if (arg == string("dtb")) 120245803Stheraven { 121245803Stheraven read_fn = &device_tree::parse_dtb; 122245803Stheraven } 123245803Stheraven else if (arg == string("dts")) 124245803Stheraven { 125245803Stheraven read_fn = &device_tree::parse_dts; 126245803Stheraven } 127245803Stheraven else 128245803Stheraven { 129245803Stheraven fprintf(stderr, "Unknown input format: %s\n", optarg); 130245803Stheraven return EXIT_FAILURE; 131245803Stheraven } 132245803Stheraven break; 133245803Stheraven } 134245803Stheraven case 'O': 135245803Stheraven { 136245803Stheraven string arg = string(optarg); 137245803Stheraven if (arg == string("dtb")) 138245803Stheraven { 139245803Stheraven write_fn = &device_tree::write_binary; 140245803Stheraven } 141245803Stheraven else if (arg == string("asm")) 142245803Stheraven { 143245803Stheraven write_fn = &device_tree::write_asm; 144245803Stheraven } 145245803Stheraven else if (arg == string("dts")) 146245803Stheraven { 147245803Stheraven write_fn = &device_tree::write_dts; 148245803Stheraven } 149245803Stheraven else 150245803Stheraven { 151245803Stheraven fprintf(stderr, "Unknown output format: %s\n", optarg); 152245803Stheraven return EXIT_FAILURE; 153245803Stheraven } 154245803Stheraven break; 155245803Stheraven } 156245803Stheraven case 'o': 157245803Stheraven { 158245803Stheraven outfile_name = optarg; 159245803Stheraven outfile = open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 0666); 160245803Stheraven if (outfile == -1) 161245803Stheraven { 162245803Stheraven perror("Unable to open output file"); 163245803Stheraven return EXIT_FAILURE; 164245803Stheraven } 165245803Stheraven break; 166245803Stheraven } 167245803Stheraven case 'D': 168245803Stheraven debug_mode = true; 169245803Stheraven break; 170245803Stheraven case 'V': 171245807Stheraven if (string(optarg) != string("17")) 172245803Stheraven { 173245803Stheraven fprintf(stderr, "Unknown output format version: %s\n", optarg); 174245803Stheraven return EXIT_FAILURE; 175245803Stheraven } 176245803Stheraven break; 177245803Stheraven case 'd': 178245803Stheraven { 179245803Stheraven if (depfile != 0) 180245803Stheraven { 181245803Stheraven fclose(depfile); 182245803Stheraven } 183245803Stheraven if (string(optarg) == string("-")) 184245803Stheraven { 185245803Stheraven depfile = stdout; 186245803Stheraven } 187245803Stheraven else 188245803Stheraven { 189245803Stheraven depfile = fdopen(open(optarg, O_CREAT | O_TRUNC | O_WRONLY, 0666), "w"); 190245803Stheraven if (depfile == 0) 191245803Stheraven { 192245803Stheraven perror("Unable to open dependency file"); 193245803Stheraven return EXIT_FAILURE; 194245803Stheraven } 195245803Stheraven } 196245803Stheraven break; 197245803Stheraven } 198245803Stheraven case 'H': 199245803Stheraven { 200245803Stheraven string arg = string(optarg); 201245803Stheraven if (arg == string("both")) 202245803Stheraven { 203245803Stheraven tree.set_phandle_format(device_tree::BOTH); 204245803Stheraven } 205245803Stheraven else if (arg == string("epapr")) 206245803Stheraven { 207245803Stheraven tree.set_phandle_format(device_tree::EPAPR); 208245803Stheraven } 209245803Stheraven else if (arg == string("linux")) 210245803Stheraven { 211245803Stheraven tree.set_phandle_format(device_tree::LINUX); 212245803Stheraven } 213245803Stheraven else 214245803Stheraven { 215245803Stheraven fprintf(stderr, "Unknown phandle format: %s\n", optarg); 216245803Stheraven return EXIT_FAILURE; 217245803Stheraven } 218245803Stheraven break; 219245803Stheraven } 220245803Stheraven case 'b': 221245803Stheraven // Don't bother to check if strtoll fails, just 222245803Stheraven // use the 0 it returns. 223245803Stheraven boot_cpu = (uint32_t)strtoll(optarg, 0, 10); 224245803Stheraven boot_cpu_specified = true; 225245803Stheraven break; 226245803Stheraven case 'f': 227245803Stheraven keep_going = true; 228245803Stheraven break; 229245803Stheraven case 'W': 230245803Stheraven case 'E': 231245803Stheraven { 232245803Stheraven string arg = string(optarg); 233245803Stheraven if ((arg.size() > 3) && (strncmp(optarg, "no-", 3) == 0)) 234245803Stheraven { 235245803Stheraven arg = string(optarg+3); 236245803Stheraven if (!checks.disable_checker(arg)) 237245803Stheraven { 238245803Stheraven fprintf(stderr, "Checker %s either does not exist or is already disabled\n", optarg+3); 239245803Stheraven } 240245803Stheraven break; 241245803Stheraven } 242245803Stheraven if (!checks.enable_checker(arg)) 243245803Stheraven { 244245803Stheraven fprintf(stderr, "Checker %s either does not exist or is already enabled\n", optarg); 245245803Stheraven } 246245803Stheraven break; 247245803Stheraven } 248245803Stheraven case 's': 249245803Stheraven { 250245803Stheraven sort = true; 251245803Stheraven break; 252245803Stheraven } 253245803Stheraven case 'i': 254245803Stheraven { 255245803Stheraven tree.add_include_path(optarg); 256245803Stheraven break; 257245803Stheraven } 258245803Stheraven // Should quiet warnings, but for now is silently ignored. 259245803Stheraven case 'q': 260245803Stheraven break; 261245803Stheraven case 'R': 262245803Stheraven tree.set_empty_reserve_map_entries(strtoll(optarg, 0, 10)); 263245803Stheraven break; 264245803Stheraven case 'S': 265245803Stheraven tree.set_blob_minimum_size(strtoll(optarg, 0, 10)); 266245803Stheraven break; 267245803Stheraven case 'p': 268245803Stheraven tree.set_blob_padding(strtoll(optarg, 0, 10)); 269245803Stheraven break; 270254522Stheraven case 'P': 271254522Stheraven if (!tree.parse_define(optarg)) 272254522Stheraven { 273254522Stheraven fprintf(stderr, "Invalid predefine value %s\n", 274254522Stheraven optarg); 275254522Stheraven } 276254522Stheraven break; 277245803Stheraven default: 278245803Stheraven fprintf(stderr, "Unknown option %c\n", ch); 279245803Stheraven return EXIT_FAILURE; 280245803Stheraven } 281245803Stheraven } 282245803Stheraven if (optind < argc) 283245803Stheraven { 284245803Stheraven in_file = argv[optind]; 285245803Stheraven } 286245803Stheraven if (depfile != 0) 287245803Stheraven { 288245803Stheraven fputs(outfile_name, depfile); 289245803Stheraven fputs(": ", depfile); 290245803Stheraven fputs(in_file, depfile); 291245803Stheraven } 292245803Stheraven clock_t c1 = clock(); 293245803Stheraven (tree.*read_fn)(in_file, depfile); 294245803Stheraven // Override the boot CPU found in the header, if we're loading from dtb 295245803Stheraven if (boot_cpu_specified) 296245803Stheraven { 297245803Stheraven tree.set_boot_cpu(boot_cpu); 298245803Stheraven } 299245803Stheraven if (sort) 300245803Stheraven { 301245803Stheraven tree.sort(); 302245803Stheraven } 303245803Stheraven if (depfile != 0) 304245803Stheraven { 305245803Stheraven putc('\n', depfile); 306245803Stheraven fclose(depfile); 307245803Stheraven } 308245803Stheraven if (!(tree.is_valid() || keep_going)) 309245803Stheraven { 310245803Stheraven fprintf(stderr, "Failed to parse tree. Unhappy face!\n"); 311245803Stheraven return EXIT_FAILURE; 312245803Stheraven } 313245803Stheraven clock_t c2 = clock(); 314245803Stheraven if (!(checks.run_checks(&tree, true) || keep_going)) 315245803Stheraven { 316245803Stheraven return EXIT_FAILURE; 317245803Stheraven } 318245803Stheraven clock_t c3 = clock(); 319245803Stheraven (tree.*write_fn)(outfile); 320245803Stheraven close(outfile); 321245803Stheraven clock_t c4 = clock(); 322245803Stheraven 323245803Stheraven if (debug_mode) 324245803Stheraven { 325245803Stheraven struct rusage r; 326245803Stheraven 327245803Stheraven getrusage(RUSAGE_SELF, &r); 328245803Stheraven fprintf(stderr, "Peak memory usage: %ld bytes\n", r.ru_maxrss); 329245803Stheraven fprintf(stderr, "Setup and option parsing took %f seconds\n", 330245803Stheraven ((double)(c1-c0))/CLOCKS_PER_SEC); 331245803Stheraven fprintf(stderr, "Parsing took %f seconds\n", 332245803Stheraven ((double)(c2-c1))/CLOCKS_PER_SEC); 333245803Stheraven fprintf(stderr, "Checking took %f seconds\n", 334245803Stheraven ((double)(c3-c2))/CLOCKS_PER_SEC); 335245803Stheraven fprintf(stderr, "Generating output took %f seconds\n", 336245803Stheraven ((double)(c4-c3))/CLOCKS_PER_SEC); 337245803Stheraven fprintf(stderr, "Total time: %f seconds\n", 338245803Stheraven ((double)(c4-c0))/CLOCKS_PER_SEC); 339245803Stheraven // This is not needed, but keeps valgrind quiet. 340245803Stheraven fclose(stdin); 341245803Stheraven } 342245803Stheraven return EXIT_SUCCESS; 343245803Stheraven} 344245803Stheraven 345