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