tools: mkimage: use common ALIGN to do the size align
[oweals/u-boot.git] / tools / ifdtool.c
index a4b481fb60b45d7769fb48d5098a889d68d09f57..3a39b7bc701194e6bf1e9b0cb767c2feb7abca39 100644 (file)
@@ -1,10 +1,9 @@
+// SPDX-License-Identifier: GPL-2.0
 /*
  * ifdtool - Manage Intel Firmware Descriptor information
  *
  * Copyright 2014 Google, Inc
  *
- * SPDX-License-Identifier:    GPL-2.0
- *
  * From Coreboot project, but it got a serious code clean-up
  * and a few new features
  */
 #include <assert.h>
 #include <fcntl.h>
 #include <getopt.h>
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+#include <linux/libfdt.h>
 #include "ifdtool.h"
 
 #undef DEBUG
 #define FLREG_BASE(reg)                ((reg & 0x00000fff) << 12);
 #define FLREG_LIMIT(reg)       (((reg & 0x0fff0000) >> 4) | 0xfff);
 
+struct input_file {
+       char *fname;
+       unsigned int addr;
+};
+
 /**
  * find_fd() - Find the flash description in the ROM image
  *
@@ -54,7 +60,8 @@ static struct fdbar_t *find_fd(char *image, int size)
                return NULL;
        }
 
-       debug("Found Flash Descriptor signature at 0x%08x\n", i);
+       debug("Found Flash Descriptor signature at 0x%08lx\n",
+             (char *)ptr - image);
 
        return (struct fdbar_t *)ptr;
 }
@@ -448,7 +455,7 @@ static int write_regions(char *image, int size)
                if (ret)
                        return ret;
                dump_region(i, frba);
-               if (region.size == 0)
+               if (region.size <= 0)
                        continue;
                region_fd = open(region_filename(i),
                                 O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
@@ -464,6 +471,16 @@ static int write_regions(char *image, int size)
        return ret;
 }
 
+static int perror_fname(const char *fmt, const char *fname)
+{
+       char msg[strlen(fmt) + strlen(fname) + 1];
+
+       sprintf(msg, fmt, fname);
+       perror(msg);
+
+       return -1;
+}
+
 /**
  * write_image() - Write the image to a file
  *
@@ -480,10 +497,10 @@ static int write_image(char *filename, char *image, int size)
 
        new_fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR |
                      S_IWUSR | S_IRGRP | S_IROTH);
-       if (write(new_fd, image, size) != size) {
-               perror("Error while writing");
-               return -1;
-       }
+       if (new_fd < 0)
+               return perror_fname("Could not open file '%s'", filename);
+       if (write(new_fd, image, size) != size)
+               return perror_fname("Could not write file '%s'", filename);
        close(new_fd);
 
        return 0;
@@ -585,14 +602,10 @@ int open_for_read(const char *fname, int *sizep)
        int fd = open(fname, O_RDONLY);
        struct stat buf;
 
-       if (fd == -1) {
-               perror("Could not open file");
-               return -1;
-       }
-       if (fstat(fd, &buf) == -1) {
-               perror("Could not stat file");
-               return -1;
-       }
+       if (fd == -1)
+               return perror_fname("Could not open file '%s'", fname);
+       if (fstat(fd, &buf) == -1)
+               return perror_fname("Could not stat file '%s'", fname);
        *sizep = buf.st_size;
        debug("File %s is %d bytes\n", fname, *sizep);
 
@@ -686,10 +699,13 @@ int inject_region(char *image, int size, int region_type, char *region_fname)
  *                     0xffffffff so use an address relative to that. For an
  *                     8MB ROM the start address is 0xfff80000.
  * @write_fname:       Filename to add to the image
- * @return 0 if OK, -ve on error
+ * @offset_uboot_top:  Offset of the top of U-Boot
+ * @offset_uboot_start:        Offset of the start of U-Boot
+ * @return number of bytes written if OK, -ve on error
  */
 static int write_data(char *image, int size, unsigned int addr,
-                     const char *write_fname)
+                     const char *write_fname, int offset_uboot_top,
+                     int offset_uboot_start)
 {
        int write_fd, write_size;
        int offset;
@@ -698,7 +714,27 @@ static int write_data(char *image, int size, unsigned int addr,
        if (write_fd < 0)
                return write_fd;
 
-       offset = addr + size;
+       offset = (uint32_t)(addr + size);
+       if (offset_uboot_top) {
+               if (offset_uboot_start < offset &&
+                   offset_uboot_top >= offset) {
+                       fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+                               write_fname);
+                       fprintf(stderr,
+                               "U-Boot finishes at offset %x, file starts at %x\n",
+                               offset_uboot_top, offset);
+                       return -EXDEV;
+               }
+               if (offset_uboot_start > offset &&
+                   offset_uboot_start <= offset + write_size) {
+                       fprintf(stderr, "U-Boot image overlaps with region '%s'\n",
+                               write_fname);
+                       fprintf(stderr,
+                               "U-Boot starts at offset %x, file finishes at %x\n",
+                               offset_uboot_start, offset + write_size);
+                       return -EXDEV;
+               }
+       }
        debug("Writing %s to offset %#x\n", write_fname, offset);
 
        if (offset < 0 || offset + write_size > size) {
@@ -714,14 +750,14 @@ static int write_data(char *image, int size, unsigned int addr,
 
        close(write_fd);
 
-       return 0;
+       return write_size;
 }
 
 static void print_version(void)
 {
        printf("ifdtool v%s -- ", IFDTOOL_VERSION);
        printf("Copyright (C) 2014 Google Inc.\n\n");
-       printf("SPDX-License-Identifier:        GPL-2.0+\n");
+       printf("SPDX-License-Identifier: GPL-2.0+\n");
 }
 
 static void print_usage(const char *name)
@@ -732,6 +768,7 @@ static void print_usage(const char *name)
               "   -x | --extract:                   extract intel fd modules\n"
               "   -i | --inject <region>:<module>   inject file <module> into region <region>\n"
               "   -w | --write <addr>:<file>        write file to appear at memory address <addr>\n"
+              "                                     multiple files can be written simultaneously\n"
               "   -s | --spifreq <20|33|50>         set the SPI frequency\n"
               "   -e | --em100                      set SPI frequency to 20MHz and disable\n"
               "                                     Dual Output Fast Read Support\n"
@@ -778,17 +815,19 @@ int main(int argc, char *argv[])
        int mode_spifreq = 0, mode_em100 = 0, mode_locked = 0;
        int mode_unlocked = 0, mode_write = 0, mode_write_descriptor = 0;
        int create = 0;
-       char *region_type_string = NULL, *src_fname = NULL;
-       char *addr_str = NULL;
+       char *region_type_string = NULL, *inject_fname = NULL;
+       char *desc_fname = NULL, *addr_str = NULL;
        int region_type = -1, inputfreq = 0;
        enum spi_frequency spifreq = SPI_FREQUENCY_20MHZ;
-       unsigned int addr = 0;
+       struct input_file input_file[WRITE_MAX], *ifile, *fdt = NULL;
+       unsigned char wr_idx, wr_num = 0;
        int rom_size = -1;
        bool write_it;
        char *filename;
        char *outfile = NULL;
        struct stat buf;
        int size = 0;
+       bool have_uboot = false;
        int bios_fd;
        char *image;
        int ret;
@@ -798,18 +837,20 @@ int main(int argc, char *argv[])
                {"descriptor", 1, NULL, 'D'},
                {"em100", 0, NULL, 'e'},
                {"extract", 0, NULL, 'x'},
+               {"fdt", 1, NULL, 'f'},
                {"inject", 1, NULL, 'i'},
                {"lock", 0, NULL, 'l'},
                {"romsize", 1, NULL, 'r'},
                {"spifreq", 1, NULL, 's'},
                {"unlock", 0, NULL, 'u'},
+               {"uboot", 1, NULL, 'U'},
                {"write", 1, NULL, 'w'},
                {"version", 0, NULL, 'v'},
                {"help", 0, NULL, 'h'},
                {0, 0, 0, 0}
        };
 
-       while ((opt = getopt_long(argc, argv, "cdD:ehi:lr:s:uvw:x?",
+       while ((opt = getopt_long(argc, argv, "cdD:ef:hi:lr:s:uU:vw:x?",
                                  long_options, &option_index)) != EOF) {
                switch (opt) {
                case 'c':
@@ -820,14 +861,14 @@ int main(int argc, char *argv[])
                        break;
                case 'D':
                        mode_write_descriptor = 1;
-                       src_fname = optarg;
+                       desc_fname = optarg;
                        break;
                case 'e':
                        mode_em100 = 1;
                        break;
                case 'i':
                        if (get_two_words(optarg, &region_type_string,
-                                         &src_fname)) {
+                                         &inject_fname)) {
                                print_usage(argv[0]);
                                exit(EXIT_FAILURE);
                        }
@@ -885,12 +926,23 @@ int main(int argc, char *argv[])
                        exit(EXIT_SUCCESS);
                        break;
                case 'w':
+               case 'U':
+               case 'f':
+                       ifile = &input_file[wr_num];
                        mode_write = 1;
-                       if (get_two_words(optarg, &addr_str, &src_fname)) {
-                               print_usage(argv[0]);
-                               exit(EXIT_FAILURE);
+                       if (wr_num < WRITE_MAX) {
+                               if (get_two_words(optarg, &addr_str,
+                                                 &ifile->fname)) {
+                                       print_usage(argv[0]);
+                                       exit(EXIT_FAILURE);
+                               }
+                               ifile->addr = strtoll(optarg, NULL, 0);
+                               wr_num++;
+                       } else {
+                               fprintf(stderr,
+                                       "The number of files to write simultaneously exceeds the limitation (%d)\n",
+                                       WRITE_MAX);
                        }
-                       addr = strtol(optarg, NULL, 0);
                        break;
                case 'x':
                        mode_extract = 1;
@@ -941,6 +993,13 @@ int main(int argc, char *argv[])
                exit(EXIT_FAILURE);
        }
 
+       if (have_uboot && !fdt) {
+               fprintf(stderr,
+                       "You must supply a device tree file for U-Boot\n\n");
+               print_usage(argv[0]);
+               exit(EXIT_FAILURE);
+       }
+
        filename = argv[optind];
        if (optind + 2 != argc)
                outfile = argv[optind + 1];
@@ -997,13 +1056,24 @@ int main(int argc, char *argv[])
        }
 
        if (mode_write_descriptor)
-               ret = write_data(image, size, -size, src_fname);
+               ret = write_data(image, size, -size, desc_fname, 0, 0);
 
        if (mode_inject)
-               ret = inject_region(image, size, region_type, src_fname);
-
-       if (mode_write)
-               ret = write_data(image, size, addr, src_fname);
+               ret = inject_region(image, size, region_type, inject_fname);
+
+       if (mode_write) {
+               int offset_uboot_top = 0;
+               int offset_uboot_start = 0;
+
+               for (wr_idx = 0; wr_idx < wr_num; wr_idx++) {
+                       ifile = &input_file[wr_idx];
+                       ret = write_data(image, size, ifile->addr,
+                                        ifile->fname, offset_uboot_top,
+                                        offset_uboot_start);
+                       if (ret < 0)
+                               break;
+               }
+       }
 
        if (mode_spifreq)
                set_spi_frequency(image, size, spifreq);
@@ -1035,5 +1105,5 @@ int main(int argc, char *argv[])
        free(image);
        close(bios_fd);
 
-       return ret ? 1 : 0;
+       return ret < 0 ? 1 : 0;
 }