Merge branch 'master' of git://git.denx.de/u-boot-arm
[kernel/u-boot.git] / tools / fit_image.c
1 /*
2  * (C) Copyright 2008 Semihalf
3  *
4  * (C) Copyright 2000-2004
5  * DENX Software Engineering
6  * Wolfgang Denk, wd@denx.de
7  *
8  * Updated-by: Prafulla Wadaskar <prafulla@marvell.com>
9  *              FIT image specific code abstracted from mkimage.c
10  *              some functions added to address abstraction
11  *
12  * All rights reserved.
13  *
14  * SPDX-License-Identifier:     GPL-2.0+
15  */
16
17 #include "mkimage.h"
18 #include <image.h>
19 #include <u-boot/crc.h>
20
21 static image_header_t header;
22
23 static int fit_verify_header (unsigned char *ptr, int image_size,
24                         struct mkimage_params *params)
25 {
26         return fdt_check_header(ptr);
27 }
28
29 static int fit_check_image_types (uint8_t type)
30 {
31         if (type == IH_TYPE_FLATDT)
32                 return EXIT_SUCCESS;
33         else
34                 return EXIT_FAILURE;
35 }
36
37 int mmap_fdt(struct mkimage_params *params, const char *fname, void **blobp,
38                 struct stat *sbuf)
39 {
40         void *ptr;
41         int fd;
42
43         /* Load FIT blob into memory (we need to write hashes/signatures) */
44         fd = open(fname, O_RDWR | O_BINARY);
45
46         if (fd < 0) {
47                 fprintf(stderr, "%s: Can't open %s: %s\n",
48                         params->cmdname, fname, strerror(errno));
49                 unlink(fname);
50                 return -1;
51         }
52
53         if (fstat(fd, sbuf) < 0) {
54                 fprintf(stderr, "%s: Can't stat %s: %s\n",
55                         params->cmdname, fname, strerror(errno));
56                 unlink(fname);
57                 return -1;
58         }
59
60         ptr = mmap(0, sbuf->st_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
61         if (ptr == MAP_FAILED) {
62                 fprintf(stderr, "%s: Can't read %s: %s\n",
63                         params->cmdname, fname, strerror(errno));
64                 unlink(fname);
65                 return -1;
66         }
67
68         /* check if ptr has a valid blob */
69         if (fdt_check_header(ptr)) {
70                 fprintf(stderr, "%s: Invalid FIT blob\n", params->cmdname);
71                 unlink(fname);
72                 return -1;
73         }
74
75         *blobp = ptr;
76         return fd;
77 }
78
79 /**
80  * fit_handle_file - main FIT file processing function
81  *
82  * fit_handle_file() runs dtc to convert .its to .itb, includes
83  * binary data, updates timestamp property and calculates hashes.
84  *
85  * datafile  - .its file
86  * imagefile - .itb file
87  *
88  * returns:
89  *     only on success, otherwise calls exit (EXIT_FAILURE);
90  */
91 static int fit_handle_file (struct mkimage_params *params)
92 {
93         char tmpfile[MKIMAGE_MAX_TMPFILE_LEN];
94         char cmd[MKIMAGE_MAX_DTC_CMDLINE_LEN];
95         int tfd, destfd = 0;
96         void *dest_blob = NULL;
97         struct stat sbuf;
98         void *ptr;
99         off_t destfd_size = 0;
100
101         /* Flattened Image Tree (FIT) format  handling */
102         debug ("FIT format handling\n");
103
104         /* call dtc to include binary properties into the tmp file */
105         if (strlen (params->imagefile) +
106                 strlen (MKIMAGE_TMPFILE_SUFFIX) + 1 > sizeof (tmpfile)) {
107                 fprintf (stderr, "%s: Image file name (%s) too long, "
108                                 "can't create tmpfile",
109                                 params->imagefile, params->cmdname);
110                 return (EXIT_FAILURE);
111         }
112         sprintf (tmpfile, "%s%s", params->imagefile, MKIMAGE_TMPFILE_SUFFIX);
113
114         /* We either compile the source file, or use the existing FIT image */
115         if (params->datafile) {
116                 /* dtc -I dts -O dtb -p 500 datafile > tmpfile */
117                 snprintf(cmd, sizeof(cmd), "%s %s %s > %s",
118                          MKIMAGE_DTC, params->dtc, params->datafile, tmpfile);
119                 debug("Trying to execute \"%s\"\n", cmd);
120         } else {
121                 snprintf(cmd, sizeof(cmd), "cp %s %s",
122                          params->imagefile, tmpfile);
123         }
124         if (system (cmd) == -1) {
125                 fprintf (stderr, "%s: system(%s) failed: %s\n",
126                                 params->cmdname, cmd, strerror(errno));
127                 goto err_system;
128         }
129
130         if (params->keydest) {
131                 destfd = mmap_fdt(params, params->keydest, &dest_blob, &sbuf);
132                 if (destfd < 0)
133                         goto err_keydest;
134                 destfd_size = sbuf.st_size;
135         }
136
137         tfd = mmap_fdt(params, tmpfile, &ptr, &sbuf);
138         if (tfd < 0)
139                 goto err_mmap;
140
141         /* set hashes for images in the blob */
142         if (fit_add_verification_data(params->keydir,
143                                       dest_blob, ptr, params->comment,
144                                       params->require_keys)) {
145                 fprintf(stderr, "%s Can't add hashes to FIT blob\n",
146                         params->cmdname);
147                 goto err_add_hashes;
148         }
149
150         /* for first image creation, add a timestamp at offset 0 i.e., root  */
151         if (params->datafile && fit_set_timestamp(ptr, 0, sbuf.st_mtime)) {
152                 fprintf (stderr, "%s: Can't add image timestamp\n",
153                                 params->cmdname);
154                 goto err_add_timestamp;
155         }
156         debug ("Added timestamp successfully\n");
157
158         munmap ((void *)ptr, sbuf.st_size);
159         close (tfd);
160         if (dest_blob) {
161                 munmap(dest_blob, destfd_size);
162                 close(destfd);
163         }
164
165         if (rename (tmpfile, params->imagefile) == -1) {
166                 fprintf (stderr, "%s: Can't rename %s to %s: %s\n",
167                                 params->cmdname, tmpfile, params->imagefile,
168                                 strerror (errno));
169                 unlink (tmpfile);
170                 unlink (params->imagefile);
171                 return (EXIT_FAILURE);
172         }
173         return (EXIT_SUCCESS);
174
175 err_add_timestamp:
176 err_add_hashes:
177         munmap(ptr, sbuf.st_size);
178 err_mmap:
179         if (dest_blob)
180                 munmap(dest_blob, destfd_size);
181 err_keydest:
182 err_system:
183         unlink(tmpfile);
184         return -1;
185 }
186
187 static int fit_check_params (struct mkimage_params *params)
188 {
189         return  ((params->dflag && (params->fflag || params->lflag)) ||
190                 (params->fflag && (params->dflag || params->lflag)) ||
191                 (params->lflag && (params->dflag || params->fflag)));
192 }
193
194 static struct image_type_params fitimage_params = {
195         .name = "FIT Image support",
196         .header_size = sizeof(image_header_t),
197         .hdr = (void*)&header,
198         .verify_header = fit_verify_header,
199         .print_header = fit_print_contents,
200         .check_image_type = fit_check_image_types,
201         .fflag_handle = fit_handle_file,
202         .set_header = NULL,     /* FIT images use DTB header */
203         .check_params = fit_check_params,
204 };
205
206 void init_fit_image_type (void)
207 {
208         mkimage_register (&fitimage_params);
209 }