1 /* SPDX-License-Identifier: GPL-2.0-only */ 2 /* 3 * mkrkboot - build the Android boot image booted by Rockchip's U-Boot 4 * together with the Rockchip resource image carrying the device tree 5 */ 6 #include <errno.h> 7 #include <getopt.h> 8 #include <stdint.h> 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <string.h> 12 13 #include "sha1.h" 14 15 #define BLOCK_SIZE 512 16 #define SHA1_LEN 20 17 #define MAX_ENTRIES 16 18 19 #define BOOT_MAGIC "ANDROID!" 20 #define BOOT_NAME_LEN 16 21 #define BOOT_CMDLINE_LEN 512 22 #define BOOT_ID_LEN 32 23 #define BOOT_EXTRA_LEN 1024 24 #define BOOT_OFF_KERNEL_SIZE 8 25 #define BOOT_OFF_KERNEL_ADDR 12 26 #define BOOT_OFF_SECOND_SIZE 24 27 #define BOOT_OFF_SECOND_ADDR 28 28 #define BOOT_OFF_TAGS_ADDR 32 29 #define BOOT_OFF_PAGE_SIZE 36 30 #define BOOT_OFF_NAME 48 31 #define BOOT_OFF_CMDLINE (BOOT_OFF_NAME + BOOT_NAME_LEN) 32 #define BOOT_OFF_ID (BOOT_OFF_CMDLINE + BOOT_CMDLINE_LEN) 33 #define BOOT_HDR_SIZE (BOOT_OFF_ID + BOOT_ID_LEN + BOOT_EXTRA_LEN) 34 35 #define RES_MAGIC "RSCE" 36 #define RES_ENTRY_MAGIC "ENTR" 37 #define RES_PATH_LEN 220 38 #define RES_HASH_LEN 32 39 #define RES_OFF_HDR_BLOCKS 8 40 #define RES_OFF_TABLE_BLOCK 9 41 #define RES_OFF_ENTRY_BLOCKS 10 42 #define RES_OFF_COUNT 12 43 #define RES_OFF_PATH 4 44 #define RES_OFF_HASH (RES_OFF_PATH + RES_PATH_LEN) 45 #define RES_OFF_HASH_SIZE (RES_OFF_HASH + RES_HASH_LEN) 46 #define RES_OFF_OFFSET (RES_OFF_HASH_SIZE + 4) 47 #define RES_OFF_SIZE (RES_OFF_OFFSET + 4) 48 49 struct blob { 50 uint8_t *data; 51 size_t len; 52 }; 53 54 struct res_entry { 55 char *path; 56 struct blob blob; 57 }; 58 59 static void put_le32(uint8_t *buf, uint32_t val) 60 { 61 buf[0] = val & 0xff; 62 buf[1] = (val >> 8) & 0xff; 63 buf[2] = (val >> 16) & 0xff; 64 buf[3] = val >> 24; 65 } 66 67 static size_t round_up(size_t val, size_t align) 68 { 69 return (val + align - 1) / align * align; 70 } 71 72 static int blob_read(const char *path, struct blob *blob) 73 { 74 FILE *fp; 75 long len; 76 77 fp = fopen(path, "rb"); 78 if (!fp) { 79 fprintf(stderr, "%s: %s\n", path, strerror(errno)); 80 return -1; 81 } 82 if (fseek(fp, 0, SEEK_END) || (len = ftell(fp)) < 0 || 83 fseek(fp, 0, SEEK_SET)) { 84 fprintf(stderr, "%s: cannot determine size\n", path); 85 fclose(fp); 86 return -1; 87 } 88 blob->len = len; 89 blob->data = malloc(len ? len : 1); 90 if (!blob->data || fread(blob->data, 1, len, fp) != (size_t)len) { 91 fprintf(stderr, "%s: read failed\n", path); 92 fclose(fp); 93 return -1; 94 } 95 fclose(fp); 96 return 0; 97 } 98 99 static int blob_write(const char *path, const struct blob *blob) 100 { 101 FILE *fp; 102 103 fp = fopen(path, "wb"); 104 if (!fp) { 105 fprintf(stderr, "%s: %s\n", path, strerror(errno)); 106 return -1; 107 } 108 if (fwrite(blob->data, 1, blob->len, fp) != blob->len || 109 fclose(fp)) { 110 fprintf(stderr, "%s: write failed\n", path); 111 return -1; 112 } 113 return 0; 114 } 115 116 static int res_build(struct res_entry *entries, int count, 117 struct blob *out) 118 { 119 size_t table = BLOCK_SIZE + (size_t)count * BLOCK_SIZE; 120 size_t offset; 121 size_t total; 122 uint8_t *ent; 123 int i; 124 125 total = table; 126 for (i = 0; i < count; i++) 127 total += round_up(entries[i].blob.len, BLOCK_SIZE); 128 129 out->data = calloc(1, total); 130 if (!out->data) 131 return -1; 132 out->len = total; 133 134 memcpy(out->data, RES_MAGIC, 4); 135 out->data[RES_OFF_HDR_BLOCKS] = 1; 136 out->data[RES_OFF_TABLE_BLOCK] = 1; 137 out->data[RES_OFF_ENTRY_BLOCKS] = 1; 138 put_le32(out->data + RES_OFF_COUNT, count); 139 140 offset = count + 1; 141 for (i = 0; i < count; i++) { 142 ent = out->data + BLOCK_SIZE + (size_t)i * BLOCK_SIZE; 143 memcpy(ent, RES_ENTRY_MAGIC, 4); 144 strncpy((char *)ent + RES_OFF_PATH, entries[i].path, 145 RES_PATH_LEN - 1); 146 sha1_csum(entries[i].blob.data, entries[i].blob.len, 147 ent + RES_OFF_HASH); 148 put_le32(ent + RES_OFF_HASH_SIZE, SHA1_LEN); 149 put_le32(ent + RES_OFF_OFFSET, offset); 150 put_le32(ent + RES_OFF_SIZE, entries[i].blob.len); 151 memcpy(out->data + offset * BLOCK_SIZE, entries[i].blob.data, 152 entries[i].blob.len); 153 offset += round_up(entries[i].blob.len, BLOCK_SIZE) / 154 BLOCK_SIZE; 155 } 156 return 0; 157 } 158 159 static int boot_build(const struct blob *kernel, const struct blob *second, 160 uint32_t kernel_addr, uint32_t second_addr, 161 uint32_t tags_addr, const char *name, 162 const char *cmdline, size_t page, struct blob *out) 163 { 164 size_t kernel_pad = round_up(kernel->len, page); 165 size_t second_pad = round_up(second->len, page); 166 size_t hdr_pad = round_up(BOOT_HDR_SIZE, page); 167 uint8_t len_le[4]; 168 sha1_context sha; 169 uint8_t *hdr; 170 171 out->len = hdr_pad + kernel_pad + second_pad; 172 out->data = calloc(1, out->len); 173 if (!out->data) 174 return -1; 175 176 hdr = out->data; 177 memcpy(hdr, BOOT_MAGIC, 8); 178 put_le32(hdr + BOOT_OFF_KERNEL_SIZE, kernel->len); 179 put_le32(hdr + BOOT_OFF_KERNEL_ADDR, kernel_addr); 180 put_le32(hdr + BOOT_OFF_SECOND_SIZE, second->len); 181 put_le32(hdr + BOOT_OFF_SECOND_ADDR, second_addr); 182 put_le32(hdr + BOOT_OFF_TAGS_ADDR, tags_addr); 183 put_le32(hdr + BOOT_OFF_PAGE_SIZE, page); 184 strncpy((char *)hdr + BOOT_OFF_NAME, name, BOOT_NAME_LEN - 1); 185 strncpy((char *)hdr + BOOT_OFF_CMDLINE, cmdline, 186 BOOT_CMDLINE_LEN - 1); 187 188 /* kernel, empty ramdisk and second stage, each followed by its size */ 189 sha1_starts(&sha); 190 sha1_update(&sha, kernel->data, kernel->len); 191 put_le32(len_le, kernel->len); 192 sha1_update(&sha, len_le, 4); 193 put_le32(len_le, 0); 194 sha1_update(&sha, len_le, 4); 195 sha1_update(&sha, second->data, second->len); 196 put_le32(len_le, second->len); 197 sha1_update(&sha, len_le, 4); 198 sha1_finish(&sha, hdr + BOOT_OFF_ID); 199 200 memcpy(out->data + hdr_pad, kernel->data, kernel->len); 201 memcpy(out->data + hdr_pad + kernel_pad, second->data, second->len); 202 return 0; 203 } 204 205 static void usage(const char *progname) 206 { 207 fprintf(stderr, 208 "Usage: %s -k <kernel> -d <dtb> -o <output> [options]\n" 209 "\n" 210 "Options:\n" 211 " -k <file> kernel image\n" 212 " -d <file> device tree, stored as rk-kernel.dtb\n" 213 " -e <name=file> additional resource image entry\n" 214 " -o <file> output boot image\n" 215 " -a <addr> kernel load address\n" 216 " -f <addr> resource image load address\n" 217 " -t <addr> kernel tags address\n" 218 " -c <string> kernel command line\n" 219 " -n <string> image name\n" 220 " -p <size> page size (default 2048)\n" 221 " -h show this help\n", 222 progname); 223 } 224 225 int main(int argc, char *argv[]) 226 { 227 uint32_t kernel_addr = 0, second_addr = 0, tags_addr = 0; 228 struct res_entry entries[MAX_ENTRIES]; 229 const char *cmdline = "", *name = ""; 230 struct blob resource, kernel, boot; 231 const char *kernel_path = NULL; 232 const char *out_path = NULL; 233 const char *dtb_path = NULL; 234 size_t page = 2048; 235 int count = 1; 236 char *sep; 237 int opt; 238 int i; 239 240 while ((opt = getopt(argc, argv, "k:d:e:o:a:f:t:c:n:p:h")) != -1) { 241 switch (opt) { 242 case 'k': 243 kernel_path = optarg; 244 break; 245 case 'd': 246 dtb_path = optarg; 247 break; 248 case 'e': 249 sep = strchr(optarg, '='); 250 if (!sep || count >= MAX_ENTRIES) { 251 usage(argv[0]); 252 return EXIT_FAILURE; 253 } 254 *sep = '\0'; 255 entries[count].path = optarg; 256 if (blob_read(sep + 1, &entries[count].blob)) 257 return EXIT_FAILURE; 258 count++; 259 break; 260 case 'o': 261 out_path = optarg; 262 break; 263 case 'a': 264 kernel_addr = strtoul(optarg, NULL, 0); 265 break; 266 case 'f': 267 second_addr = strtoul(optarg, NULL, 0); 268 break; 269 case 't': 270 tags_addr = strtoul(optarg, NULL, 0); 271 break; 272 case 'c': 273 cmdline = optarg; 274 break; 275 case 'n': 276 name = optarg; 277 break; 278 case 'p': 279 page = strtoul(optarg, NULL, 0); 280 break; 281 default: 282 usage(argv[0]); 283 return opt == 'h' ? EXIT_SUCCESS : EXIT_FAILURE; 284 } 285 } 286 287 if (!kernel_path || !dtb_path || !out_path || !page) { 288 usage(argv[0]); 289 return EXIT_FAILURE; 290 } 291 292 entries[0].path = "rk-kernel.dtb"; 293 if (blob_read(dtb_path, &entries[0].blob) || 294 blob_read(kernel_path, &kernel)) 295 return EXIT_FAILURE; 296 297 for (i = 0; i < count; i++) { 298 if (strlen(entries[i].path) >= RES_PATH_LEN) { 299 fprintf(stderr, "%s: path too long\n", entries[i].path); 300 return EXIT_FAILURE; 301 } 302 } 303 304 if (res_build(entries, count, &resource) || 305 boot_build(&kernel, &resource, kernel_addr, second_addr, 306 tags_addr, name, cmdline, page, &boot)) { 307 fprintf(stderr, "out of memory\n"); 308 return EXIT_FAILURE; 309 } 310 311 return blob_write(out_path, &boot) ? EXIT_FAILURE : EXIT_SUCCESS; 312 } 313
This page was automatically generated by LXR 0.3.1. • OpenWrt