blob: bb1528e1a8f3f09b14492cbd300d36a3de2ec2e3 [file] [log] [blame]
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +07001/* tools/mkbootimg/mkbootimg.c
2**
3** Copyright 2007, The Android Open Source Project
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +07004** Copyright 2013, Sony Mobile Communications
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +07005**
6** Licensed under the Apache License, Version 2.0 (the "License");
7** you may not use this file except in compliance with the License.
8** You may obtain a copy of the License at
9**
10** http://www.apache.org/licenses/LICENSE-2.0
11**
12** Unless required by applicable law or agreed to in writing, software
13** distributed under the License is distributed on an "AS IS" BASIS,
14** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15** See the License for the specific language governing permissions and
16** limitations under the License.
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +070017**
18** June 2014, Ketut Putu Kumajaya
19** Modified for Samsung Exynos DTBH, based on mkqcdtbootimg from Sony
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +070020*/
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <string.h>
25#include <unistd.h>
26#include <fcntl.h>
27#include <errno.h>
Christopher N. Hessed17a69b2016-12-29 21:24:37 +010028#include <limits.h>
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +070029
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +070030#include <sys/types.h>
31#include <arpa/inet.h>
32#include <assert.h>
33#include <dirent.h>
34#include <err.h>
35#include <stdint.h>
36
Christopher N. Hesse7e73d2e2016-12-30 00:11:33 +010037#include <dtbimg.h>
Christopher N. Hesse357950e2016-12-29 20:32:22 +010038
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +070039#include "mincrypt/sha.h"
40#include "bootimg.h"
41
42static void *load_file(const char *fn, unsigned *_sz)
43{
44 char *data;
45 int sz;
46 int fd;
47
48 data = 0;
49 fd = open(fn, O_RDONLY);
50 if(fd < 0) return 0;
51
52 sz = lseek(fd, 0, SEEK_END);
53 if(sz < 0) goto oops;
54
55 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
56
57 data = (char*) malloc(sz);
58 if(data == 0) goto oops;
59
60 if(read(fd, data, sz) != sz) goto oops;
61 close(fd);
62
63 if(_sz) *_sz = sz;
64 return data;
65
66oops:
67 close(fd);
68 if(data != 0) free(data);
69 return 0;
70}
71
72int usage(void)
73{
74 fprintf(stderr,"usage: mkbootimg\n"
75 " --kernel <filename>\n"
76 " --ramdisk <filename>\n"
77 " [ --second <2ndbootloader-filename> ]\n"
78 " [ --cmdline <kernel-commandline> ]\n"
79 " [ --board <boardname> ]\n"
80 " [ --base <address> ]\n"
81 " [ --pagesize <pagesize> ]\n"
82 " [ --ramdisk_offset <address> ]\n"
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +070083 " [ --dt_dir <dtb path> ]\n"
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +070084 " [ --dt <filename> ]\n"
Ketut Putu Kumajaya0c2cc5a2014-06-23 20:18:46 +070085 " [ --signature <filename> ]\n"
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +070086 " -o|--output <filename>\n"
87 );
88 return 1;
89}
90
91
92
93static unsigned char padding[131072] = { 0, };
94
95int write_padding(int fd, unsigned pagesize, unsigned itemsize)
96{
97 unsigned pagemask = pagesize - 1;
98 unsigned count;
99
100 if((itemsize & pagemask) == 0) {
101 return 0;
102 }
103
104 count = pagesize - (itemsize & pagemask);
105
106 if(write(fd, padding, count) != count) {
107 return -1;
108 } else {
109 return 0;
110 }
111}
112
113int main(int argc, char **argv)
114{
115 boot_img_hdr hdr;
116
117 char *kernel_fn = 0;
118 void *kernel_data = 0;
119 char *ramdisk_fn = 0;
120 void *ramdisk_data = 0;
121 char *second_fn = 0;
122 void *second_data = 0;
123 char *cmdline = "";
124 char *bootimg = 0;
125 char *board = "";
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +0700126 char *dt_dir = 0;
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700127 char *dt_fn = 0;
128 void *dt_data = 0;
Ketut Putu Kumajaya0c2cc5a2014-06-23 20:18:46 +0700129 char *sig_fn = 0;
130 void *sig_data = 0;
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700131 unsigned pagesize = 2048;
132 int fd;
133 SHA_CTX ctx;
134 uint8_t* sha;
135 unsigned base = 0x10000000;
136 unsigned kernel_offset = 0x00008000;
137 unsigned ramdisk_offset = 0x01000000;
138 unsigned second_offset = 0x00f00000;
139 unsigned tags_offset = 0x00000100;
140
141 argc--;
142 argv++;
143
144 memset(&hdr, 0, sizeof(hdr));
145
146 while(argc > 0){
147 char *arg = argv[0];
148 char *val = argv[1];
149 if(argc < 2) {
150 return usage();
151 }
152 argc -= 2;
153 argv += 2;
154 if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
155 bootimg = val;
156 } else if(!strcmp(arg, "--kernel")) {
157 kernel_fn = val;
158 } else if(!strcmp(arg, "--ramdisk")) {
159 ramdisk_fn = val;
160 } else if(!strcmp(arg, "--second")) {
161 second_fn = val;
162 } else if(!strcmp(arg, "--cmdline")) {
163 cmdline = val;
164 } else if(!strcmp(arg, "--base")) {
165 base = strtoul(val, 0, 16);
166 } else if(!strcmp(arg, "--kernel_offset")) {
167 kernel_offset = strtoul(val, 0, 16);
168 } else if(!strcmp(arg, "--ramdisk_offset")) {
169 ramdisk_offset = strtoul(val, 0, 16);
170 } else if(!strcmp(arg, "--second_offset")) {
171 second_offset = strtoul(val, 0, 16);
172 } else if(!strcmp(arg, "--tags_offset")) {
173 tags_offset = strtoul(val, 0, 16);
174 } else if(!strcmp(arg, "--board")) {
175 board = val;
176 } else if(!strcmp(arg,"--pagesize")) {
177 pagesize = strtoul(val, 0, 10);
178 if ((pagesize != 2048) && (pagesize != 4096) && (pagesize != 8192) && (pagesize != 16384) && (pagesize != 32768) && (pagesize != 65536) && (pagesize != 131072)) {
179 fprintf(stderr,"error: unsupported page size %d\n", pagesize);
180 return -1;
181 }
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +0700182 } else if (!strcmp(arg, "--dt_dir")) {
183 dt_dir = val;
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700184 } else if(!strcmp(arg, "--dt")) {
185 dt_fn = val;
Ketut Putu Kumajaya0c2cc5a2014-06-23 20:18:46 +0700186 } else if(!strcmp(arg, "--signature")) {
187 sig_fn = val;
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700188 } else {
189 return usage();
190 }
191 }
192 hdr.page_size = pagesize;
193
194 hdr.kernel_addr = base + kernel_offset;
195 hdr.ramdisk_addr = base + ramdisk_offset;
196 hdr.second_addr = base + second_offset;
197 hdr.tags_addr = base + tags_offset;
198
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +0700199 if (dt_dir && dt_fn) {
200 fprintf(stderr,"error: don't use both --dt_dir and --dt option\n");
201 return usage();
202 }
203
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700204 if(bootimg == 0) {
205 fprintf(stderr,"error: no output filename specified\n");
206 return usage();
207 }
208
209 if(kernel_fn == 0) {
210 fprintf(stderr,"error: no kernel image specified\n");
211 return usage();
212 }
213
214 if(ramdisk_fn == 0) {
215 fprintf(stderr,"error: no ramdisk image specified\n");
216 return usage();
217 }
218
219 if(strlen(board) >= BOOT_NAME_SIZE) {
220 fprintf(stderr,"error: board name too large\n");
221 return usage();
222 }
223
224 strcpy(hdr.name, board);
225
226 memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
227
228 if(strlen(cmdline) > (BOOT_ARGS_SIZE - 1)) {
229 fprintf(stderr,"error: kernel commandline too large\n");
230 return 1;
231 }
232 strcpy((char*)hdr.cmdline, cmdline);
233
234 kernel_data = load_file(kernel_fn, &hdr.kernel_size);
235 if(kernel_data == 0) {
236 fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
237 return 1;
238 }
239
240 if(!strcmp(ramdisk_fn,"NONE")) {
241 ramdisk_data = 0;
242 hdr.ramdisk_size = 0;
243 } else {
244 ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size);
245 if(ramdisk_data == 0) {
246 fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
247 return 1;
248 }
249 }
250
251 if(second_fn) {
252 second_data = load_file(second_fn, &hdr.second_size);
253 if(second_data == 0) {
254 fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
255 return 1;
256 }
257 }
258
Ketut Putu Kumajaya72b1c492014-06-24 16:18:20 +0700259 if (dt_dir) {
260 dt_data = load_dtbh_block(dt_dir, pagesize, &hdr.dt_size);
261 if (dt_data == 0) {
262 fprintf(stderr, "error: could not load device tree blobs '%s'\n", dt_dir);
263 return 1;
264 }
265 }
266
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700267 if(dt_fn) {
268 dt_data = load_file(dt_fn, &hdr.dt_size);
269 if (dt_data == 0) {
270 fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn);
271 return 1;
272 }
273 }
274
Ketut Putu Kumajaya0c2cc5a2014-06-23 20:18:46 +0700275 if(sig_fn) {
276 sig_data = load_file(sig_fn, 0);
277 if (sig_data == 0) {
278 fprintf(stderr,"error: could not load signature '%s'\n", sig_fn);
279 return 1;
280 }
281 }
282
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700283 /* put a hash of the contents in the header so boot images can be
284 * differentiated based on their first 2k.
285 */
286 SHA_init(&ctx);
287 SHA_update(&ctx, kernel_data, hdr.kernel_size);
288 SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size));
289 SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size);
290 SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size));
291 SHA_update(&ctx, second_data, hdr.second_size);
292 SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size));
293 if(dt_data) {
294 SHA_update(&ctx, dt_data, hdr.dt_size);
295 SHA_update(&ctx, &hdr.dt_size, sizeof(hdr.dt_size));
296 }
297 sha = SHA_final(&ctx);
298 memcpy(hdr.id, sha,
299 SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE);
300
301 fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
302 if(fd < 0) {
303 fprintf(stderr,"error: could not create '%s'\n", bootimg);
304 return 1;
305 }
306
307 if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
308 if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
309
310 if(write(fd, kernel_data, hdr.kernel_size) != hdr.kernel_size) goto fail;
311 if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
312
313 if(write(fd, ramdisk_data, hdr.ramdisk_size) != hdr.ramdisk_size) goto fail;
314 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
315
316 if(second_data) {
317 if(write(fd, second_data, hdr.second_size) != hdr.second_size) goto fail;
318 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
319 }
320
321 if(dt_data) {
322 if(write(fd, dt_data, hdr.dt_size) != hdr.dt_size) goto fail;
323 if(write_padding(fd, pagesize, hdr.dt_size)) goto fail;
324 }
Ketut Putu Kumajaya0c2cc5a2014-06-23 20:18:46 +0700325
326 if(sig_data) {
327 if(write(fd, sig_data, 256) != 256) goto fail;
328 }
329
Ketut Putu Kumajaya63846372014-06-23 20:05:33 +0700330 return 0;
331
332fail:
333 unlink(bootimg);
334 close(fd);
335 fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
336 strerror(errno));
337 return 1;
338}