blob: bc729714118b9ab0b805c0b561a5cbf3f95e1748 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/* tools/mkbootimg/mkbootimg.c
2**
3** Copyright 2007, The Android Open Source Project
4**
5** Licensed under the Apache License, Version 2.0 (the "License");
6** you may not use this file except in compliance with the License.
7** You may obtain a copy of the License at
8**
9** http://www.apache.org/licenses/LICENSE-2.0
10**
11** Unless required by applicable law or agreed to in writing, software
12** distributed under the License is distributed on an "AS IS" BASIS,
13** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14** See the License for the specific language governing permissions and
15** limitations under the License.
16*/
17
18#include <stdio.h>
19#include <stdlib.h>
20#include <string.h>
21#include <unistd.h>
22#include <fcntl.h>
23#include <errno.h>
24#include <stdbool.h>
25
26#include "mincrypt/sha.h"
27#include "mincrypt/sha256.h"
28#include "bootimg.h"
29
30static void *load_file(const char *fn, unsigned *_sz)
31{
32 char *data;
33 int sz;
34 int fd;
35
36 data = 0;
37 fd = open(fn, O_RDONLY);
38 if(fd < 0) return 0;
39
40 sz = lseek(fd, 0, SEEK_END);
41 if(sz < 0) goto oops;
42
43 if(lseek(fd, 0, SEEK_SET) != 0) goto oops;
44
45 data = (char*) malloc(sz);
46 if(data == 0) goto oops;
47
48 if(read(fd, data, sz) != sz) goto oops;
49 close(fd);
50
51 if(_sz) *_sz = sz;
52 return data;
53
54oops:
55 close(fd);
56 if(data != 0) free(data);
57 return 0;
58}
59
60int usage(void)
61{
62 fprintf(stderr,"usage: mkbootimg\n"
63 " --kernel <filename>\n"
64 " [ --ramdisk <filename> ]\n"
65 " [ --second <2ndbootloader-filename> ]\n"
66 " [ --cmdline <kernel-commandline> ]\n"
67 " [ --board <boardname> ]\n"
68 " [ --base <address> ]\n"
69 " [ --pagesize <pagesize> ]\n"
70 " [ --dt <filename> ]\n"
71 " [ --kernel_offset <base offset> ]\n"
72 " [ --ramdisk_offset <base offset> ]\n"
73 " [ --second_offset <base offset> ]\n"
74 " [ --tags_offset <base offset> ]\n"
75 " [ --os_version <A.B.C version> ]\n"
76 " [ --os_patch_level <YYYY-MM-DD date> ]\n"
77 " [ --hash <sha1(default)|sha256> ]\n"
78 " [ --id ]\n"
79 " -o|--output <filename>\n"
80 );
81 return 1;
82}
83
84
85
86static unsigned char padding[131072] = { 0, };
87
88static void print_id(const uint8_t *id, size_t id_len) {
89 printf("0x");
90 unsigned i = 0;
91 for (i = 0; i < id_len; i++) {
92 printf("%02x", id[i]);
93 }
94 printf("\n");
95}
96
97int write_padding(int fd, unsigned pagesize, unsigned itemsize)
98{
99 unsigned pagemask = pagesize - 1;
100 ssize_t count;
101
102 if((itemsize & pagemask) == 0) {
103 return 0;
104 }
105
106 count = pagesize - (itemsize & pagemask);
107
108 if(write(fd, padding, count) != count) {
109 return -1;
110 } else {
111 return 0;
112 }
113}
114
115int parse_os_version(char *ver)
116{
117 char *token;
118 int verArray[3] = {0};
119 int a,b,c = 0;
120 int i = 0;
121
122 token = strtok(ver, ".");
123 while(token != NULL) {
124 sscanf(token, "%d", &verArray[i]);
125 token = strtok(NULL, ".");
126 i++;
127 }
128 a = verArray[0];
129 b = verArray[1];
130 c = verArray[2];
131 if((a < 128) && (b < 128) && (c < 128))
132 return (a << 14) | (b << 7) | c;
133 return 0;
134}
135
136int parse_os_patch_level(char *lvl)
137{
138 char *token;
139 int lvlArray[2] = {0};
140 int y,m = 0;
141 int i = 0;
142
143 token = strtok(lvl, "-");
144 while(token != NULL) {
145 sscanf(token, "%d", &lvlArray[i]);
146 token = strtok(NULL, "-");
147 i++;
148 }
149 y = lvlArray[0] - 2000;
150 m = lvlArray[1];
151 if((y >= 0) && (y < 128) && (m > 0) && (m <= 12))
152 return (y << 4) | m;
153 return 0;
154}
155
156enum hash_alg {
157 HASH_UNKNOWN = -1,
158 HASH_SHA1 = 0,
159 HASH_SHA256,
160};
161
162struct hash_name {
163 const char *name;
164 enum hash_alg alg;
165};
166
167const struct hash_name hash_names[] = {
168 { "sha1", HASH_SHA1 },
169 { "sha256", HASH_SHA256 },
170 { NULL, /* Sentinel */ },
171};
172
173enum hash_alg parse_hash_alg(char *name)
174{
175 const struct hash_name *ptr = hash_names;
176
177 while (ptr->name) {
178 if (!strcmp(ptr->name, name))
179 return ptr->alg;
180 ptr++;
181 }
182
183 return HASH_UNKNOWN;
184}
185
186void generate_id_sha1(boot_img_hdr *hdr, void *kernel_data, void *ramdisk_data,
187 void *second_data, void *dt_data)
188{
189 SHA_CTX ctx;
190 const uint8_t *sha;
191
192 SHA_init(&ctx);
193 SHA_update(&ctx, kernel_data, hdr->kernel_size);
194 SHA_update(&ctx, &hdr->kernel_size, sizeof(hdr->kernel_size));
195 SHA_update(&ctx, ramdisk_data, hdr->ramdisk_size);
196 SHA_update(&ctx, &hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
197 SHA_update(&ctx, second_data, hdr->second_size);
198 SHA_update(&ctx, &hdr->second_size, sizeof(hdr->second_size));
199 if(dt_data) {
200 SHA_update(&ctx, dt_data, hdr->dt_size);
201 SHA_update(&ctx, &hdr->dt_size, sizeof(hdr->dt_size));
202 }
203 sha = SHA_final(&ctx);
204 memcpy(hdr->id, sha,
205 SHA_DIGEST_SIZE > sizeof(hdr->id) ? sizeof(hdr->id) : SHA_DIGEST_SIZE);
206}
207
208void generate_id_sha256(boot_img_hdr *hdr, void *kernel_data, void *ramdisk_data,
209 void *second_data, void *dt_data)
210{
211 SHA256_CTX ctx;
212 const uint8_t *sha;
213
214 SHA256_init(&ctx);
215 SHA256_update(&ctx, kernel_data, hdr->kernel_size);
216 SHA256_update(&ctx, &hdr->kernel_size, sizeof(hdr->kernel_size));
217 SHA256_update(&ctx, ramdisk_data, hdr->ramdisk_size);
218 SHA256_update(&ctx, &hdr->ramdisk_size, sizeof(hdr->ramdisk_size));
219 SHA256_update(&ctx, second_data, hdr->second_size);
220 SHA256_update(&ctx, &hdr->second_size, sizeof(hdr->second_size));
221 if(dt_data) {
222 SHA256_update(&ctx, dt_data, hdr->dt_size);
223 SHA256_update(&ctx, &hdr->dt_size, sizeof(hdr->dt_size));
224 }
225 sha = SHA256_final(&ctx);
226 memcpy(hdr->id, sha,
227 SHA256_DIGEST_SIZE > sizeof(hdr->id) ? sizeof(hdr->id) : SHA256_DIGEST_SIZE);
228}
229
230void generate_id(enum hash_alg alg, boot_img_hdr *hdr, void *kernel_data,
231 void *ramdisk_data, void *second_data, void *dt_data)
232{
233 switch (alg) {
234 case HASH_SHA1:
235 generate_id_sha1(hdr, kernel_data, ramdisk_data,
236 second_data, dt_data);
237 break;
238 case HASH_SHA256:
239 generate_id_sha256(hdr, kernel_data, ramdisk_data,
240 second_data, dt_data);
241 break;
242 case HASH_UNKNOWN:
243 default:
244 fprintf(stderr, "Unknown hash type.\n");
245 }
246}
247
248int main(int argc, char **argv)
249{
250 boot_img_hdr hdr;
251
252 char *kernel_fn = NULL;
253 void *kernel_data = NULL;
254 char *ramdisk_fn = NULL;
255 void *ramdisk_data = NULL;
256 char *second_fn = NULL;
257 void *second_data = NULL;
258 char *cmdline = "";
259 char *bootimg = NULL;
260 char *board = "";
261 int os_version = 0;
262 int os_patch_level = 0;
263 char *dt_fn = NULL;
264 void *dt_data = NULL;
265 uint32_t pagesize = 2048;
266 int fd;
267 uint32_t base = 0x10000000U;
268 uint32_t kernel_offset = 0x00008000U;
269 uint32_t ramdisk_offset = 0x01000000U;
270 uint32_t second_offset = 0x00f00000U;
271 uint32_t tags_offset = 0x00000100U;
272 uint32_t kernel_sz = 0;
273 uint32_t ramdisk_sz = 0;
274 uint32_t second_sz = 0;
275 uint32_t dt_sz = 0;
276 size_t cmdlen;
277 enum hash_alg hash_alg = HASH_SHA1;
278
279 argc--;
280 argv++;
281
282 memset(&hdr, 0, sizeof(hdr));
283
284 bool get_id = false;
285 while(argc > 0){
286 char *arg = argv[0];
287 if (!strcmp(arg, "--id")) {
288 get_id = true;
289 argc -= 1;
290 argv += 1;
291 } else if(argc >= 2) {
292 char *val = argv[1];
293 argc -= 2;
294 argv += 2;
295 if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) {
296 bootimg = val;
297 } else if(!strcmp(arg, "--kernel")) {
298 kernel_fn = val;
299 } else if(!strcmp(arg, "--ramdisk")) {
300 ramdisk_fn = val;
301 } else if(!strcmp(arg, "--second")) {
302 second_fn = val;
303 } else if(!strcmp(arg, "--cmdline")) {
304 cmdline = val;
305 } else if(!strcmp(arg, "--base")) {
306 base = strtoul(val, 0, 16);
307 } else if(!strcmp(arg, "--kernel_offset")) {
308 kernel_offset = strtoul(val, 0, 16);
309 } else if(!strcmp(arg, "--ramdisk_offset")) {
310 ramdisk_offset = strtoul(val, 0, 16);
311 } else if(!strcmp(arg, "--second_offset")) {
312 second_offset = strtoul(val, 0, 16);
313 } else if(!strcmp(arg, "--tags_offset")) {
314 tags_offset = strtoul(val, 0, 16);
315 } else if(!strcmp(arg, "--board")) {
316 board = val;
317 } else if(!strcmp(arg,"--pagesize")) {
318 pagesize = strtoul(val, 0, 10);
319 if ((pagesize != 2048) && (pagesize != 4096)
320 && (pagesize != 8192) && (pagesize != 16384)
321 && (pagesize != 32768) && (pagesize != 65536)
322 && (pagesize != 131072)) {
323 fprintf(stderr,"error: unsupported page size %d\n", pagesize);
324 return -1;
325 }
326 } else if(!strcmp(arg, "--dt")) {
327 dt_fn = val;
328 } else if(!strcmp(arg, "--os_version")) {
329 os_version = parse_os_version(val);
330 } else if(!strcmp(arg, "--os_patch_level")) {
331 os_patch_level = parse_os_patch_level(val);
332 } else if(!strcmp(arg, "--hash")) {
333 hash_alg = parse_hash_alg(val);
334 if (hash_alg == HASH_UNKNOWN) {
335 fprintf(stderr, "error: unknown hash algorithm '%s'\n", val);
336 return -1;
337 }
338 } else {
339 return usage();
340 }
341 } else {
342 return usage();
343 }
344 }
345 hdr.page_size = pagesize;
346
347 hdr.kernel_addr = base + kernel_offset;
348 hdr.ramdisk_addr = base + ramdisk_offset;
349 hdr.second_addr = base + second_offset;
350 hdr.tags_addr = base + tags_offset;
351
352 hdr.os_version = (os_version << 11) | os_patch_level;
353
354 if(bootimg == 0) {
355 fprintf(stderr,"error: no output filename specified\n");
356 return usage();
357 }
358
359 if(kernel_fn == 0) {
360 fprintf(stderr,"error: no kernel image specified\n");
361 return usage();
362 }
363
364 if(strlen(board) >= BOOT_NAME_SIZE) {
365 fprintf(stderr,"error: board name too large\n");
366 return usage();
367 }
368
369 strcpy((char *) hdr.name, board);
370
371 memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE);
372
373 cmdlen = strlen(cmdline);
374 if(cmdlen <= BOOT_ARGS_SIZE) {
375 strcpy((char *)hdr.cmdline, cmdline);
376 } else if(cmdlen <= BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE) {
377 /* exceeds the limits of the base command-line size, go for the extra */
378 memcpy(hdr.cmdline, cmdline, BOOT_ARGS_SIZE);
379 strcpy((char *)hdr.extra_cmdline, cmdline+BOOT_ARGS_SIZE);
380 } else {
381 fprintf(stderr,"error: kernel commandline too large\n");
382 return 1;
383 }
384
385 kernel_data = load_file(kernel_fn, &kernel_sz);
386 if(kernel_data == 0) {
387 fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn);
388 return 1;
389 }
390 hdr.kernel_size = kernel_sz;
391
392 if(ramdisk_fn == NULL) {
393 ramdisk_data = 0;
394 hdr.ramdisk_size = 0;
395 } else {
396 ramdisk_data = load_file(ramdisk_fn, &ramdisk_sz);
397 if(ramdisk_data == 0) {
398 fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn);
399 return 1;
400 }
401 hdr.ramdisk_size = ramdisk_sz;
402 }
403
404 if(second_fn) {
405 second_data = load_file(second_fn, &second_sz);
406 if(second_data == 0) {
407 fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn);
408 return 1;
409 }
410 }
411 hdr.second_size = second_sz;
412
413 if(dt_fn) {
414 dt_data = load_file(dt_fn, &dt_sz);
415 if (dt_data == 0) {
416 fprintf(stderr,"error: could not load device tree image '%s'\n", dt_fn);
417 return 1;
418 }
419 }
420 hdr.dt_size = dt_sz;
421
422 /* put a hash of the contents in the header so boot images can be
423 * differentiated based on their first 2k.
424 */
425 generate_id(hash_alg, &hdr, kernel_data, ramdisk_data, second_data,
426 dt_data);
427
428 fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644);
429 if(fd < 0) {
430 fprintf(stderr,"error: could not create '%s'\n", bootimg);
431 return 1;
432 }
433
434 if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail;
435 if(write_padding(fd, pagesize, sizeof(hdr))) goto fail;
436
437 if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail;
438 if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail;
439
440 if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail;
441 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail;
442
443 if(second_data) {
444 if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail;
445 if(write_padding(fd, pagesize, hdr.second_size)) goto fail;
446 }
447
448 if(dt_data) {
449 if(write(fd, dt_data, hdr.dt_size) != (ssize_t) hdr.dt_size) goto fail;
450 if(write_padding(fd, pagesize, hdr.dt_size)) goto fail;
451 }
452
453 if (get_id) {
454 print_id((uint8_t *) hdr.id, sizeof(hdr.id));
455 }
456 return 0;
457
458fail:
459 unlink(bootimg);
460 close(fd);
461 fprintf(stderr,"error: failed writing '%s': %s\n", bootimg,
462 strerror(errno));
463 return 1;
464}