linux/scripts/dtc/fdtoverlay.c
<<
>>
Prefs
   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. */
  24static 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;
  29static const char usage_short_opts[] = "i:o:v" USAGE_COMMON_SHORT_OPTS;
  30static 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};
  36static 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
  43int verbose = 0;
  44
  45static 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
  86fail:
  87        free(tmpo);
  88        if (tmp)
  89                free(tmp);
  90
  91        return NULL;
  92}
  93static 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
 150out_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
 163int 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