• source navigation  • diff markup  • identifier search  • freetext search  • 

Sources/firmware-utils/src/mkrkboot.c

  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