1 /* 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 "bootimg.h" 28 29 static void *load_file(const char *fn, unsigned *_sz) 30 { 31 char *data; 32 int sz; 33 int fd; 34 35 data = 0; 36 fd = open(fn, O_RDONLY); 37 if(fd < 0) return 0; 38 39 sz = lseek(fd, 0, SEEK_END); 40 if(sz < 0) goto oops; 41 42 if(lseek(fd, 0, SEEK_SET) != 0) goto oops; 43 44 data = (char*) malloc(sz); 45 if(data == 0) goto oops; 46 47 if(read(fd, data, sz) != sz) goto oops; 48 close(fd); 49 50 if(_sz) *_sz = sz; 51 return data; 52 53 oops: 54 close(fd); 55 if(data != 0) free(data); 56 return 0; 57 } 58 59 int usage(void) 60 { 61 fprintf(stderr,"usage: mkbootimg\n" 62 " --kernel <filename>\n" 63 " [ --ramdisk <filename> ]\n" 64 " [ --second <2ndbootloader-filename> ]\n" 65 " [ --cmdline <kernel-commandline> ]\n" 66 " [ --board <boardname> ]\n" 67 " [ --base <address> ]\n" 68 " [ --pagesize <pagesize> ]\n" 69 " [ --id ]\n" 70 " -o|--output <filename>\n" 71 ); 72 return 1; 73 } 74 75 76 77 static unsigned char padding[16384] = { 0, }; 78 79 static void print_id(const uint8_t *id, size_t id_len) { 80 printf("0x"); 81 for (unsigned i = 0; i < id_len; i++) { 82 printf("%02x", id[i]); 83 } 84 printf("\n"); 85 } 86 87 int write_padding(int fd, unsigned pagesize, unsigned itemsize) 88 { 89 unsigned pagemask = pagesize - 1; 90 ssize_t count; 91 92 if((itemsize & pagemask) == 0) { 93 return 0; 94 } 95 96 count = pagesize - (itemsize & pagemask); 97 98 if(write(fd, padding, count) != count) { 99 return -1; 100 } else { 101 return 0; 102 } 103 } 104 105 int main(int argc, char **argv) 106 { 107 boot_img_hdr hdr; 108 109 char *kernel_fn = NULL; 110 void *kernel_data = NULL; 111 char *ramdisk_fn = NULL; 112 void *ramdisk_data = NULL; 113 char *second_fn = NULL; 114 void *second_data = NULL; 115 char *cmdline = ""; 116 char *bootimg = NULL; 117 char *board = ""; 118 uint32_t pagesize = 2048; 119 int fd; 120 SHA_CTX ctx; 121 const uint8_t* sha; 122 uint32_t base = 0x10000000U; 123 uint32_t kernel_offset = 0x00008000U; 124 uint32_t ramdisk_offset = 0x01000000U; 125 uint32_t second_offset = 0x00f00000U; 126 uint32_t tags_offset = 0x00000100U; 127 size_t cmdlen; 128 129 argc--; 130 argv++; 131 132 memset(&hdr, 0, sizeof(hdr)); 133 134 bool get_id = false; 135 while(argc > 0){ 136 char *arg = argv[0]; 137 if (!strcmp(arg, "--id")) { 138 get_id = true; 139 argc -= 1; 140 argv += 1; 141 } else if(argc >= 2) { 142 char *val = argv[1]; 143 argc -= 2; 144 argv += 2; 145 if(!strcmp(arg, "--output") || !strcmp(arg, "-o")) { 146 bootimg = val; 147 } else if(!strcmp(arg, "--kernel")) { 148 kernel_fn = val; 149 } else if(!strcmp(arg, "--ramdisk")) { 150 ramdisk_fn = val; 151 } else if(!strcmp(arg, "--second")) { 152 second_fn = val; 153 } else if(!strcmp(arg, "--cmdline")) { 154 cmdline = val; 155 } else if(!strcmp(arg, "--base")) { 156 base = strtoul(val, 0, 16); 157 } else if(!strcmp(arg, "--kernel_offset")) { 158 kernel_offset = strtoul(val, 0, 16); 159 } else if(!strcmp(arg, "--ramdisk_offset")) { 160 ramdisk_offset = strtoul(val, 0, 16); 161 } else if(!strcmp(arg, "--second_offset")) { 162 second_offset = strtoul(val, 0, 16); 163 } else if(!strcmp(arg, "--tags_offset")) { 164 tags_offset = strtoul(val, 0, 16); 165 } else if(!strcmp(arg, "--board")) { 166 board = val; 167 } else if(!strcmp(arg,"--pagesize")) { 168 pagesize = strtoul(val, 0, 10); 169 if ((pagesize != 2048) && (pagesize != 4096) 170 && (pagesize != 8192) && (pagesize != 16384)) { 171 fprintf(stderr,"error: unsupported page size %d\n", pagesize); 172 return -1; 173 } 174 } else { 175 return usage(); 176 } 177 } else { 178 return usage(); 179 } 180 } 181 hdr.page_size = pagesize; 182 183 hdr.kernel_addr = base + kernel_offset; 184 hdr.ramdisk_addr = base + ramdisk_offset; 185 hdr.second_addr = base + second_offset; 186 hdr.tags_addr = base + tags_offset; 187 188 if(bootimg == 0) { 189 fprintf(stderr,"error: no output filename specified\n"); 190 return usage(); 191 } 192 193 if(kernel_fn == 0) { 194 fprintf(stderr,"error: no kernel image specified\n"); 195 return usage(); 196 } 197 198 if(strlen(board) >= BOOT_NAME_SIZE) { 199 fprintf(stderr,"error: board name too large\n"); 200 return usage(); 201 } 202 203 strcpy((char *) hdr.name, board); 204 205 memcpy(hdr.magic, BOOT_MAGIC, BOOT_MAGIC_SIZE); 206 207 cmdlen = strlen(cmdline); 208 if(cmdlen > (BOOT_ARGS_SIZE + BOOT_EXTRA_ARGS_SIZE - 2)) { 209 fprintf(stderr,"error: kernel commandline too large\n"); 210 return 1; 211 } 212 /* Even if we need to use the supplemental field, ensure we 213 * are still NULL-terminated */ 214 strncpy((char *)hdr.cmdline, cmdline, BOOT_ARGS_SIZE - 1); 215 hdr.cmdline[BOOT_ARGS_SIZE - 1] = '\0'; 216 if (cmdlen >= (BOOT_ARGS_SIZE - 1)) { 217 cmdline += (BOOT_ARGS_SIZE - 1); 218 strncpy((char *)hdr.extra_cmdline, cmdline, BOOT_EXTRA_ARGS_SIZE); 219 } 220 221 kernel_data = load_file(kernel_fn, &hdr.kernel_size); 222 if(kernel_data == 0) { 223 fprintf(stderr,"error: could not load kernel '%s'\n", kernel_fn); 224 return 1; 225 } 226 227 if(ramdisk_fn == 0) { 228 ramdisk_data = 0; 229 hdr.ramdisk_size = 0; 230 } else { 231 ramdisk_data = load_file(ramdisk_fn, &hdr.ramdisk_size); 232 if(ramdisk_data == 0) { 233 fprintf(stderr,"error: could not load ramdisk '%s'\n", ramdisk_fn); 234 return 1; 235 } 236 } 237 238 if(second_fn) { 239 second_data = load_file(second_fn, &hdr.second_size); 240 if(second_data == 0) { 241 fprintf(stderr,"error: could not load secondstage '%s'\n", second_fn); 242 return 1; 243 } 244 } 245 246 /* put a hash of the contents in the header so boot images can be 247 * differentiated based on their first 2k. 248 */ 249 SHA_init(&ctx); 250 SHA_update(&ctx, kernel_data, hdr.kernel_size); 251 SHA_update(&ctx, &hdr.kernel_size, sizeof(hdr.kernel_size)); 252 SHA_update(&ctx, ramdisk_data, hdr.ramdisk_size); 253 SHA_update(&ctx, &hdr.ramdisk_size, sizeof(hdr.ramdisk_size)); 254 SHA_update(&ctx, second_data, hdr.second_size); 255 SHA_update(&ctx, &hdr.second_size, sizeof(hdr.second_size)); 256 sha = SHA_final(&ctx); 257 memcpy(hdr.id, sha, 258 SHA_DIGEST_SIZE > sizeof(hdr.id) ? sizeof(hdr.id) : SHA_DIGEST_SIZE); 259 260 fd = open(bootimg, O_CREAT | O_TRUNC | O_WRONLY, 0644); 261 if(fd < 0) { 262 fprintf(stderr,"error: could not create '%s'\n", bootimg); 263 return 1; 264 } 265 266 if(write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) goto fail; 267 if(write_padding(fd, pagesize, sizeof(hdr))) goto fail; 268 269 if(write(fd, kernel_data, hdr.kernel_size) != (ssize_t) hdr.kernel_size) goto fail; 270 if(write_padding(fd, pagesize, hdr.kernel_size)) goto fail; 271 272 if(write(fd, ramdisk_data, hdr.ramdisk_size) != (ssize_t) hdr.ramdisk_size) goto fail; 273 if(write_padding(fd, pagesize, hdr.ramdisk_size)) goto fail; 274 275 if(second_data) { 276 if(write(fd, second_data, hdr.second_size) != (ssize_t) hdr.second_size) goto fail; 277 if(write_padding(fd, pagesize, hdr.second_size)) goto fail; 278 } 279 280 if (get_id) { 281 print_id((uint8_t *) hdr.id, sizeof(hdr.id)); 282 } 283 284 return 0; 285 286 fail: 287 unlink(bootimg); 288 close(fd); 289 fprintf(stderr,"error: failed writing '%s': %s\n", bootimg, 290 strerror(errno)); 291 return 1; 292 } 293