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>]]\n" 27 "\n" 28 USAGE_TYPE_MSG; 29 static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS; 30 static struct option const usage_long_opts[] = { 31 {"input", required_argument, NULL, 'i'}, 32 {"output", required_argument, NULL, 'o'}, 33 {"verbose", no_argument, NULL, 'v'}, 34 USAGE_COMMON_LONG_OPTS, 35 }; 36 static const char * const usage_opts_help[] = { 37 "Input base DT blob", 38 "Output DT blob", 39 "Verbose messages", 40 USAGE_COMMON_OPTS_HELP 41 }; 42 43 int verbose = 0; 44 45 static void *apply_one(char *base, const char *overlay, size_t *buf_len, 46 const char *name) 47 { 48 char *tmp = NULL; 49 char *tmpo; 50 int ret; 51 52 /* 53 * We take a copies first, because a a failed apply can trash 54 * both the base blob and the overlay 55 */ 56 tmpo = xmalloc(fdt_totalsize(overlay)); 57 58 do { 59 tmp = xrealloc(tmp, *buf_len); 60 ret = fdt_open_into(base, tmp, *buf_len); 61 if (ret) { 62 fprintf(stderr, 63 "\nFailed to make temporary copy: %s\n", 64 fdt_strerror(ret)); 65 goto fail; 66 } 67 68 memcpy(tmpo, overlay, fdt_totalsize(overlay)); 69 70 ret = fdt_overlay_apply(tmp, tmpo); 71 if (ret == -FDT_ERR_NOSPACE) { 72 *buf_len += BUF_INCREMENT; 73 } 74 } while (ret == -FDT_ERR_NOSPACE); 75 76 if (ret) { 77 fprintf(stderr, "\nFailed to apply '%s': %s\n", 78 name, fdt_strerror(ret)); 79 goto fail; 80 } 81 82 free(base); 83 free(tmpo); 84 return tmp; 85 86 fail: 87 free(tmpo); 88 if (tmp) 89 free(tmp); 90 91 return NULL; 92 } 93 static int do_fdtoverlay(const char *input_filename, 94 const char *output_filename, 95 int argc, char *argv[]) 96 { 97 char *blob = NULL; 98 char **ovblob = NULL; 99 size_t buf_len; 100 int i, ret = -1; 101 102 blob = utilfdt_read(input_filename, &buf_len); 103 if (!blob) { 104 fprintf(stderr, "\nFailed to read '%s'\n", input_filename); 105 goto out_err; 106 } 107 if (fdt_totalsize(blob) > buf_len) { 108 fprintf(stderr, 109 "\nBase blob is incomplete (%lu / %" PRIu32 " bytes read)\n", 110 (unsigned long)buf_len, fdt_totalsize(blob)); 111 goto out_err; 112 } 113 114 /* allocate blob pointer array */ 115 ovblob = xmalloc(sizeof(*ovblob) * argc); 116 memset(ovblob, 0, sizeof(*ovblob) * argc); 117 118 /* read and keep track of the overlay blobs */ 119 for (i = 0; i < argc; i++) { 120 size_t ov_len; 121 ovblob[i] = utilfdt_read(argv[i], &ov_len); 122 if (!ovblob[i]) { 123 fprintf(stderr, "\nFailed to read '%s'\n", argv[i]); 124 goto out_err; 125 } 126 if (fdt_totalsize(ovblob[i]) > ov_len) { 127 fprintf(stderr, 128 "\nOverlay '%s' is incomplete (%lu / %" PRIu32 " bytes read)\n", 129 argv[i], (unsigned long)ov_len, 130 fdt_totalsize(ovblob[i])); 131 goto out_err; 132 } 133 } 134 135 buf_len = fdt_totalsize(blob); 136 137 /* apply the overlays in sequence */ 138 for (i = 0; i < argc; i++) { 139 blob = apply_one(blob, ovblob[i], &buf_len, argv[i]); 140 if (!blob) 141 goto out_err; 142 } 143 144 fdt_pack(blob); 145 ret = utilfdt_write(output_filename, blob); 146 if (ret) 147 fprintf(stderr, "\nFailed to write '%s'\n", 148 output_filename); 149 150 out_err: 151 if (ovblob) { 152 for (i = 0; i < argc; i++) { 153 if (ovblob[i]) 154 free(ovblob[i]); 155 } 156 free(ovblob); 157 } 158 free(blob); 159 160 return ret; 161 } 162 163 int main(int argc, char *argv[]) 164 { 165 int opt, i; 166 char *input_filename = NULL; 167 char *output_filename = NULL; 168 169 while ((opt = util_getopt_long()) != EOF) { 170 switch (opt) { 171 case_USAGE_COMMON_FLAGS 172 173 case 'i': 174 input_filename = optarg; 175 break; 176 case 'o': 177 output_filename = optarg; 178 break; 179 case 'v': 180 verbose = 1; 181 break; 182 } 183 } 184 185 if (!input_filename) 186 usage("missing input file"); 187 188 if (!output_filename) 189 usage("missing output file"); 190 191 argv += optind; 192 argc -= optind; 193 194 if (argc <= 0) 195 usage("missing overlay file(s)"); 196 197 if (verbose) { 198 printf("input = %s\n", input_filename); 199 printf("output = %s\n", output_filename); 200 for (i = 0; i < argc; i++) 201 printf("overlay[%d] = %s\n", i, argv[i]); 202 } 203 204 if (do_fdtoverlay(input_filename, output_filename, argc, argv)) 205 return 1; 206 207 return 0; 208 } 209