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