1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * Copyright (c) 2017 Konsulko Group Inc. All rights reserved. 4 * 5 * Author: 6 * Pantelis Antoniou <pantelis.antoniou@konsulko.com> 7 */ 8 9 #include <assert.h> 10 #include <ctype.h> 11 #include <getopt.h> 12 #include <stdio.h> 13 #include <stdlib.h> 14 #include <string.h> 15 #include <inttypes.h> 16 17 #include <libfdt.h> 18 19 #include "util.h" 20 21 #define BUF_INCREMENT 65536 22 23 /* Usage related data. */ 24 static const char usage_synopsis[] = 25 "apply a number of overlays to a base blob\n" 26 " fdtoverlay <options> [<overlay.dtbo> [<overlay.dtbo>]]"; 27 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS; 28 static struct option const usage_long_opts[] = { 29 {"input", required_argument, NULL, 'i'}, 30 {"output", required_argument, NULL, 'o'}, 31 {"verbose", no_argument, NULL, 'v'}, 32 USAGE_COMMON_LONG_OPTS, 33 }; 34 static const char * const usage_opts_help[] = { 35 "Input base DT blob", 36 "Output DT blob", 37 "Verbose messages", 38 USAGE_COMMON_OPTS_HELP 39 }; 40 41 int verbose = 0; 42 43 static void *apply_one(char *base, const char *overlay, size_t *buf_len, 44 const char *name) 45 { 46 char *tmp = NULL; 47 char *tmpo; 48 int ret; 49 bool has_symbols; 50 51 /* 52 * We take copies first, because a failed apply can trash 53 * both the base blob and the overlay 54 */ 55 tmpo = xmalloc(fdt_totalsize(overlay)); 56 57 do { 58 tmp = xrealloc(tmp, *buf_len); 59 ret = fdt_open_into(base, tmp, *buf_len); 60 if (ret) { 61 fprintf(stderr, 62 "\nFailed to make temporary copy: %s\n", 63 fdt_strerror(ret)); 64 goto fail; 65 } 66 ret = fdt_path_offset(tmp, "/__symbols__"); 67 has_symbols = ret >= 0; 68 69 memcpy(tmpo, overlay, fdt_totalsize(overlay)); 70 71 ret = fdt_overlay_apply(tmp, tmpo); 72 if (ret == -FDT_ERR_NOSPACE) { 73 *buf_len += BUF_INCREMENT; 74 } 75 } while (ret == -FDT_ERR_NOSPACE); 76 77 if (ret) { 78 fprintf(stderr, "\nFailed to apply '%s': %s\n", 79 name, fdt_strerror(ret)); 80 if (!has_symbols) { 81 fprintf(stderr, 82 "base blob does not have a '/__symbols__' node, " 83 "make sure you have compiled the base blob with '-@' option\n"); 84 } 85 goto fail; 86 } 87 88 free(base); 89 free(tmpo); 90 return tmp; 91 92 fail: 93 free(tmpo); 94 if (tmp) 95 free(tmp); 96 97 return NULL; 98 } 99 static int do_fdtoverlay(const char *input_filename, 100 const char *output_filename, 101 int argc, char *argv[]) 102 { 103 char *blob = NULL; 104 char **ovblob = NULL; 105 size_t buf_len; 106 int i, ret = -1; 107 108 blob = utilfdt_read(input_filename, &buf_len); 109 if (!blob) { 110 fprintf(stderr, "\nFailed to read '%s'\n", input_filename); 111 goto out_err; 112 } 113 if (fdt_totalsize(blob) > buf_len) { 114 fprintf(stderr, 115 "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n", 116 (unsigned long)buf_len, fdt_totalsize(blob)); 117 goto out_err; 118 } 119 120 /* allocate blob pointer array */ 121 ovblob = xmalloc(sizeof(*ovblob) * argc); 122 memset(ovblob, 0, sizeof(*ovblob) * argc); 123 124 /* read and keep track of the overlay blobs */ 125 for (i = 0; i < argc; i++) { 126 size_t ov_len; 127 ovblob[i] = utilfdt_read(argv[i], &ov_len); 128 if (!ovblob[i]) { 129 fprintf(stderr, "\nFailed to read '%s'\n", argv[i]); 130 goto out_err; 131 } 132 if (fdt_totalsize(ovblob[i]) > ov_len) { 133 fprintf(stderr, 134 "\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n", 135 argv[i], (unsigned long)ov_len, 136 fdt_totalsize(ovblob[i])); 137 goto out_err; 138 } 139 } 140 141 buf_len = fdt_totalsize(blob); 142 143 /* apply the overlays in sequence */ 144 for (i = 0; i < argc; i++) { 145 blob = apply_one(blob, ovblob[i], &buf_len, argv[i]); 146 if (!blob) 147 goto out_err; 148 } 149 150 fdt_pack(blob); 151 ret = utilfdt_write(output_filename, blob); 152 if (ret) 153 fprintf(stderr, "\nFailed to write '%s'\n", 154 output_filename); 155 156 out_err: 157 if (ovblob) { 158 for (i = 0; i < argc; i++) { 159 if (ovblob[i]) 160 free(ovblob[i]); 161 } 162 free(ovblob); 163 } 164 free(blob); 165 166 return ret; 167 } 168 169 int main(int argc, char *argv[]) 170 { 171 int opt, i; 172 char *input_filename = NULL; 173 char *output_filename = NULL; 174 175 while ((opt = util_getopt_long()) != EOF) { 176 switch (opt) { 177 case_USAGE_COMMON_FLAGS 178 179 case 'i': 180 input_filename = optarg; 181 break; 182 case 'o': 183 output_filename = optarg; 184 break; 185 case 'v': 186 verbose = 1; 187 break; 188 } 189 } 190 191 if (!input_filename) 192 usage("missing input file"); 193 194 if (!output_filename) 195 usage("missing output file"); 196 197 argv += optind; 198 argc -= optind; 199 200 if (argc <= 0) 201 usage("missing overlay file(s)"); 202 203 if (verbose) { 204 printf("input = %s\n", input_filename); 205 printf("output = %s\n", output_filename); 206 for (i = 0; i < argc; i++) 207 printf("overlay[%d] = %s\n", i, argv[i]); 208 } 209 210 if (do_fdtoverlay(input_filename, output_filename, argc, argv)) 211 return 1; 212 213 return 0; 214 } 215