1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <assert.h>
18 #include <sys/types.h>
19 #include <stdbool.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <stdint.h>
24 #include <stdio.h>
25 #include <stddef.h>
26 #include <errno.h>
27 
28 #include <nanohub/nanohub.h>
29 #include <nanohub/nanoapp.h>
30 #include <nanohub/appRelocFormat.h>
31 
32 //This code assumes it is run on a LE CPU with unaligned access abilities. Sorry.
33 
34 #define FLASH_BASE  0x10000000
35 #define RAM_BASE    0x80000000
36 
37 #define FLASH_SIZE  0x10000000  //256MB ought to be enough for everyone
38 #define RAM_SIZE    0x10000000  //256MB ought to be enough for everyone
39 
40 //caution: double evaluation
41 #define IS_IN_RANGE_E(_val, _rstart, _rend) (((_val) >= (_rstart)) && ((_val) < (_rend)))
42 #define IS_IN_RANGE(_val, _rstart, _rsz)    IS_IN_RANGE_E((_val), (_rstart), ((_rstart) + (_rsz)))
43 #define IS_IN_RAM(_val)              IS_IN_RANGE(_val, RAM_BASE, RAM_SIZE)
44 #define IS_IN_FLASH(_val)            IS_IN_RANGE(_val, FLASH_BASE, FLASH_SIZE)
45 
46 
47 #define NANO_RELOC_TYPE_RAM    0
48 #define NANO_RELOC_TYPE_FLASH  1
49 #define NANO_RELOC_LAST        2 //must be <= (RELOC_TYPE_MASK >> RELOC_TYPE_SHIFT)
50 
51 struct RelocEntry {
52     uint32_t where;
53     uint32_t info;  //bottom 8 bits is type, top 24 is sym idx
54 };
55 
56 #define RELOC_TYPE_ABS_S    2
57 #define RELOC_TYPE_ABS_D    21
58 #define RELOC_TYPE_SECT     23
59 
60 
61 struct SymtabEntry {
62     uint32_t a;
63     uint32_t addr;
64     uint32_t b, c;
65 };
66 
67 struct NanoRelocEntry {
68     uint32_t ofstInRam;
69     uint8_t type;
70 };
71 
fatalUsage(const char * name,const char * msg,const char * arg)72 static void fatalUsage(const char *name, const char *msg, const char *arg)
73 {
74     if (msg && arg)
75         fprintf(stderr, "Error: %s: %s\n\n", msg, arg);
76     else if (msg)
77         fprintf(stderr, "Error: %s\n\n", msg);
78 
79     fprintf(stderr, "USAGE: %s [-v] [-k <key id>] [-a <app id>] [-r] [-n <layout name>] [-i <layout id>] <input file> [<output file>]\n"
80                     "       -v               : be verbose\n"
81                     "       -n <layout name> : app, os, key\n"
82                     "       -i <layout id>   : 1 (app), 2 (key), 3 (os)\n"
83                     "       -f <layout flags>: 16-bit hex value, stored as layout-specific flags\n"
84                     "       -a <app ID>      : 64-bit hex number != 0\n"
85                     "       -k <key ID>      : 64-bit hex number != 0\n"
86                     "       -r               : bare (no AOSP header); used only for inner OS image generation\n"
87                     "       layout ID and layout name control the same parameter, so only one of them needs to be used\n"
88                     , name);
89     exit(1);
90 }
91 
handleApp(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,uint64_t appId,bool verbose)92 static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, bool verbose)
93 {
94     uint32_t i, numRelocs, numSyms, outNumRelocs = 0, packedNanoRelocSz, j, k, lastOutType = 0, origin = 0;
95     struct NanoRelocEntry *nanoRelocs = NULL;
96     struct RelocEntry *relocs;
97     struct SymtabEntry *syms;
98     uint8_t *packedNanoRelocs;
99     uint32_t t;
100     struct BinHdr *bin;
101     int ret = -1;
102     struct SectInfo *sect;
103     struct AppInfo app;
104     uint8_t *buf = *pbuf;
105     uint32_t bufSz = bufUsed * 3 /2;
106 
107     //make buffer 50% bigger than bufUsed in case relocs grow out of hand
108     buf = reallocOrDie(buf, bufSz);
109     *pbuf = buf;
110 
111     //sanity checks
112     bin = (struct BinHdr*)buf;
113     if (bufUsed < sizeof(*bin)) {
114         fprintf(stderr, "File size too small\n");
115         goto out;
116     }
117 
118     if (bin->hdr.magic != NANOAPP_FW_MAGIC) {
119         fprintf(stderr, "Magic value is wrong: found %08" PRIX32
120                         "; expected %08" PRIX32 "\n",
121                         bin->hdr.magic, NANOAPP_FW_MAGIC);
122         goto out;
123     }
124 
125     sect = &bin->sect;
126 
127     //do some math
128     relocs = (struct RelocEntry*)(buf + sect->rel_start - FLASH_BASE);
129     syms = (struct SymtabEntry*)(buf + sect->rel_end - FLASH_BASE);
130     numRelocs = (sect->rel_end - sect->rel_start) / sizeof(struct RelocEntry);
131     numSyms = (bufUsed + FLASH_BASE - sect->rel_end) / sizeof(struct SymtabEntry);
132 
133     //sanity
134     if (numRelocs * sizeof(struct RelocEntry) + sect->rel_start != sect->rel_end) {
135         fprintf(stderr, "Relocs of nonstandard size\n");
136         goto out;
137     }
138     if (numSyms * sizeof(struct SymtabEntry) + sect->rel_end != bufUsed + FLASH_BASE) {
139         fprintf(stderr, "Syms of nonstandard size\n");
140         goto out;
141     }
142 
143     //show some info
144     fprintf(stderr, "\nRead %" PRIu32 " bytes of binary.\n", bufUsed);
145 
146     if (verbose)
147         fprintf(stderr, "Found %" PRIu32 " relocs and a %" PRIu32 "-entry symbol table\n", numRelocs, numSyms);
148 
149     //handle relocs
150     nanoRelocs = malloc(sizeof(struct NanoRelocEntry[numRelocs]));
151     if (!nanoRelocs) {
152         fprintf(stderr, "Failed to allocate a nano-reloc table\n");
153         goto out;
154     }
155 
156     for (i = 0; i < numRelocs; i++) {
157         uint32_t relocType = relocs[i].info & 0xff;
158         uint32_t whichSym = relocs[i].info >> 8;
159         uint32_t *valThereP;
160 
161         if (whichSym >= numSyms) {
162             fprintf(stderr, "Reloc %" PRIu32 " references a nonexistent symbol!\n"
163                             "INFO:\n"
164                             "        Where: 0x%08" PRIX32 "\n"
165                             "        type: %" PRIu32 "\n"
166                             "        sym: %" PRIu32 "\n",
167                 i, relocs[i].where, relocs[i].info & 0xff, whichSym);
168             goto out;
169         }
170 
171         if (verbose) {
172             const char *seg;
173 
174             fprintf(stderr, "Reloc[%3" PRIu32 "]:\n {@0x%08" PRIX32 ", type %3" PRIu32 ", -> sym[%3" PRIu32 "]: {@0x%08" PRIX32 "}, ",
175                 i, relocs[i].where, relocs[i].info & 0xff, whichSym, syms[whichSym].addr);
176 
177             if (IS_IN_RANGE_E(relocs[i].where, sect->bss_start, sect->bss_end))
178                 seg = ".bss";
179             else if (IS_IN_RANGE_E(relocs[i].where, sect->data_start, sect->data_end))
180                 seg = ".data";
181             else if (IS_IN_RANGE_E(relocs[i].where, sect->got_start, sect->got_end))
182                 seg = ".got";
183             else if (IS_IN_RANGE_E(relocs[i].where, FLASH_BASE, FLASH_BASE + sizeof(struct BinHdr)))
184                 seg = "APPHDR";
185             else
186                 seg = "???";
187 
188             fprintf(stderr, "in   %s}\n", seg);
189         }
190         /* handle relocs inside the header */
191         if (IS_IN_FLASH(relocs[i].where) && relocs[i].where - FLASH_BASE < sizeof(struct BinHdr) && relocType == RELOC_TYPE_SECT) {
192             /* relocs in header are special - runtime corrects for them */
193             if (syms[whichSym].addr) {
194                 fprintf(stderr, "Weird in-header sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
195                         i, whichSym, syms[whichSym].addr);
196                 goto out;
197             }
198 
199             valThereP = (uint32_t*)(buf + relocs[i].where - FLASH_BASE);
200             if (!IS_IN_FLASH(*valThereP)) {
201                 fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of FLASH!\n"
202                                 "INFO:\n"
203                                 "        type: %" PRIu32 "\n"
204                                 "        sym: %" PRIu32 "\n"
205                                 "        Sym Addr: 0x%08" PRIX32 "\n",
206                                 i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
207                 goto out;
208             }
209 
210             // binary header generated by objcopy, .napp header and final FW header in flash are of different size.
211             // we subtract binary header offset here, so all the entry points are relative to beginning of "sect".
212             // FW will use &sect as a base to call these vectors; no more problems with different header sizes;
213             // Assumption: offsets between sect & vec, vec & code are the same in all images (or, in a simpler words, { sect, vec, code }
214             // must go together). this is enforced by linker script, and maintained by all tools and FW download code in the OS.
215             *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
216 
217             if (verbose)
218                 fprintf(stderr, "  -> Nano reloc skipped for in-header reloc\n");
219 
220             continue; /* do not produce an output reloc */
221         }
222 
223         if (!IS_IN_RAM(relocs[i].where)) {
224             fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of RAM!\n"
225                             "INFO:\n"
226                             "        type: %" PRIu32 "\n"
227                             "        sym: %" PRIu32 "\n"
228                             "        Sym Addr: 0x%08" PRIX32 "\n",
229                             i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
230             goto out;
231         }
232 
233         valThereP = (uint32_t*)(buf + relocs[i].where + sect->data_data - RAM_BASE - FLASH_BASE);
234 
235         nanoRelocs[outNumRelocs].ofstInRam = relocs[i].where - RAM_BASE;
236 
237         switch (relocType) {
238             case RELOC_TYPE_ABS_S:
239             case RELOC_TYPE_ABS_D:
240                 t = *valThereP;
241 
242                 (*valThereP) += syms[whichSym].addr;
243 
244                 if (IS_IN_FLASH(syms[whichSym].addr)) {
245                     (*valThereP) -= FLASH_BASE + BINARY_RELOC_OFFSET;
246                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
247                 }
248                 else if (IS_IN_RAM(syms[whichSym].addr)) {
249                     (*valThereP) -= RAM_BASE;
250                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
251                 }
252                 else {
253                     fprintf(stderr, "Weird reloc %" PRIu32 " to symbol %" PRIu32 " in unknown memory space (addr 0x%08" PRIX32 ")\n",
254                             i, whichSym, syms[whichSym].addr);
255                     goto out;
256                 }
257                 if (verbose)
258                     fprintf(stderr, "  -> Abs reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
259                 break;
260 
261             case RELOC_TYPE_SECT:
262                 if (syms[whichSym].addr) {
263                     fprintf(stderr, "Weird sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
264                             i, whichSym, syms[whichSym].addr);
265                     goto out;
266                 }
267 
268                 t = *valThereP;
269 
270                 if (IS_IN_FLASH(*valThereP)) {
271                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
272                     *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
273                 }
274                 else if (IS_IN_RAM(*valThereP)) {
275                     nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
276                     *valThereP -= RAM_BASE;
277                 }
278                 else {
279                     fprintf(stderr, "Weird sec reloc %" PRIu32 " to symbol %" PRIu32
280                                     " in unknown memory space (addr 0x%08" PRIX32 ")\n",
281                                     i, whichSym, *valThereP);
282                     goto out;
283                 }
284                 if (verbose)
285                     fprintf(stderr, "  -> Sect reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
286                 break;
287 
288             default:
289                 fprintf(stderr, "Weird reloc %" PRIX32 " type %" PRIX32 " to symbol %" PRIX32 "\n", i, relocType, whichSym);
290                 goto out;
291         }
292 
293         if (verbose)
294             fprintf(stderr, "  -> Nano reloc calculated as 0x%08" PRIX32 ",0x%02" PRIX8 "\n", nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
295         outNumRelocs++;
296     }
297 
298     //sort by type and then offset
299     for (i = 0; i < outNumRelocs; i++) {
300         struct NanoRelocEntry t;
301 
302         for (k = i, j = k + 1; j < outNumRelocs; j++) {
303             if (nanoRelocs[j].type > nanoRelocs[k].type)
304                 continue;
305             if ((nanoRelocs[j].type < nanoRelocs[k].type) || (nanoRelocs[j].ofstInRam < nanoRelocs[k].ofstInRam))
306                 k = j;
307         }
308         memcpy(&t, nanoRelocs + i, sizeof(struct NanoRelocEntry));
309         memcpy(nanoRelocs + i, nanoRelocs + k, sizeof(struct NanoRelocEntry));
310         memcpy(nanoRelocs + k, &t, sizeof(struct NanoRelocEntry));
311 
312         if (verbose)
313             fprintf(stderr, "SortedReloc[%3" PRIu32 "] = {0x%08" PRIX32 ",0x%02" PRIX8 "}\n", i, nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
314     }
315 
316     //produce output nanorelocs in packed format
317     packedNanoRelocs = malloc(outNumRelocs * 6); //definitely big enough
318     packedNanoRelocSz = 0;
319     for (i = 0; i < outNumRelocs; i++) {
320         uint32_t displacement;
321 
322         if (lastOutType != nanoRelocs[i].type) {  //output type if ti changed
323             if (nanoRelocs[i].type - lastOutType == 1) {
324                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_NEXT;
325                 if (verbose)
326                     fprintf(stderr, "Out: RelocTC (1) // to 0x%02" PRIX8 "\n", nanoRelocs[i].type);
327             }
328             else {
329                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_CHG;
330                 packedNanoRelocs[packedNanoRelocSz++] = nanoRelocs[i].type - lastOutType - 1;
331                 if (verbose)
332                     fprintf(stderr, "Out: RelocTC (0x%02" PRIX8 ")  // to 0x%02" PRIX8 "\n", (uint8_t)(nanoRelocs[i].type - lastOutType - 1), nanoRelocs[i].type);
333             }
334             lastOutType = nanoRelocs[i].type;
335             origin = 0;
336         }
337         displacement = nanoRelocs[i].ofstInRam - origin;
338         origin = nanoRelocs[i].ofstInRam + 4;
339         if (displacement & 3) {
340             fprintf(stderr, "Unaligned relocs are not possible!\n");
341             exit(-5);
342         }
343         displacement /= 4;
344 
345         //might be start of a run. look into that
346         if (!displacement) {
347             for (j = 1; j + i < outNumRelocs && j < MAX_RUN_LEN && nanoRelocs[j + i].type == lastOutType && nanoRelocs[j + i].ofstInRam - nanoRelocs[j + i - 1].ofstInRam == 4; j++);
348             if (j >= MIN_RUN_LEN) {
349                 if (verbose)
350                     fprintf(stderr, "Out: Reloc0  x%" PRIX32 "\n", j);
351                 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_CONSECUTIVE;
352                 packedNanoRelocs[packedNanoRelocSz++] = j - MIN_RUN_LEN;
353                 origin = nanoRelocs[j + i - 1].ofstInRam + 4;  //reset origin to last one
354                 i += j - 1;  //loop will increment anyways, hence +1
355                 continue;
356             }
357         }
358 
359         //produce output
360         if (displacement <= MAX_8_BIT_NUM) {
361             if (verbose)
362                 fprintf(stderr, "Out: Reloc8  0x%02" PRIX32 "\n", displacement);
363             packedNanoRelocs[packedNanoRelocSz++] = displacement;
364         }
365         else if (displacement <= MAX_16_BIT_NUM) {
366             if (verbose)
367                 fprintf(stderr, "Out: Reloc16 0x%06" PRIX32 "\n", displacement);
368                         displacement -= MAX_8_BIT_NUM;
369             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_16BIT_OFST;
370             packedNanoRelocs[packedNanoRelocSz++] = displacement;
371             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
372         }
373         else if (displacement <= MAX_24_BIT_NUM) {
374             if (verbose)
375                 fprintf(stderr, "Out: Reloc24 0x%08" PRIX32 "\n", displacement);
376                         displacement -= MAX_16_BIT_NUM;
377             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_24BIT_OFST;
378             packedNanoRelocs[packedNanoRelocSz++] = displacement;
379             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
380             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
381         }
382         else  {
383             if (verbose)
384                 fprintf(stderr, "Out: Reloc32 0x%08" PRIX32 "\n", displacement);
385             packedNanoRelocs[packedNanoRelocSz++] = TOKEN_32BIT_OFST;
386             packedNanoRelocs[packedNanoRelocSz++] = displacement;
387             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
388             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
389             packedNanoRelocs[packedNanoRelocSz++] = displacement >> 24;
390         }
391     }
392 
393     //overwrite original relocs and symtab with nanorelocs and adjust sizes
394     memcpy(relocs, packedNanoRelocs, packedNanoRelocSz);
395     bufUsed -= sizeof(struct RelocEntry[numRelocs]);
396     bufUsed -= sizeof(struct SymtabEntry[numSyms]);
397     bufUsed += packedNanoRelocSz;
398     assertMem(bufUsed, bufSz);
399     sect->rel_end = sect->rel_start + packedNanoRelocSz;
400 
401     //sanity
402     if (sect->rel_end - FLASH_BASE != bufUsed) {
403         fprintf(stderr, "Relocs end and file end not coincident\n");
404         goto out;
405     }
406 
407     //adjust headers for easy access (RAM)
408     if (!IS_IN_RAM(sect->data_start) || !IS_IN_RAM(sect->data_end) || !IS_IN_RAM(sect->bss_start) ||
409         !IS_IN_RAM(sect->bss_end) || !IS_IN_RAM(sect->got_start) || !IS_IN_RAM(sect->got_end)) {
410         fprintf(stderr, "data, bss, or got not in ram\n");
411         goto out;
412     }
413     sect->data_start -= RAM_BASE;
414     sect->data_end -= RAM_BASE;
415     sect->bss_start -= RAM_BASE;
416     sect->bss_end -= RAM_BASE;
417     sect->got_start -= RAM_BASE;
418     sect->got_end -= RAM_BASE;
419 
420     //adjust headers for easy access (FLASH)
421     if (!IS_IN_FLASH(sect->data_data) || !IS_IN_FLASH(sect->rel_start) || !IS_IN_FLASH(sect->rel_end)) {
422         fprintf(stderr, "data.data, or rel not in flash\n");
423         goto out;
424     }
425     sect->data_data -= FLASH_BASE + BINARY_RELOC_OFFSET;
426     sect->rel_start -= FLASH_BASE + BINARY_RELOC_OFFSET;
427     sect->rel_end -= FLASH_BASE + BINARY_RELOC_OFFSET;
428 
429     struct ImageHeader outHeader = {
430         .aosp = (struct nano_app_binary_t) {
431             .header_version = 1,
432             .magic = NANOAPP_AOSP_MAGIC,
433             .app_id = appId,
434             .app_version = bin->hdr.appVer,
435             .flags       = 0, // encrypted (1), signed (2) (will be set by other tools)
436         },
437         .layout = (struct ImageLayout) {
438             .magic = GOOGLE_LAYOUT_MAGIC,
439             .version = 1,
440             .payload = LAYOUT_APP,
441             .flags = layoutFlags,
442         },
443     };
444     uint32_t dataOffset = sizeof(outHeader) + sizeof(app);
445     uint32_t hdrDiff = dataOffset - sizeof(*bin);
446     app.sect = bin->sect;
447     app.vec  = bin->vec;
448 
449     assertMem(bufUsed + hdrDiff, bufSz);
450 
451     memmove(buf + dataOffset, buf + sizeof(*bin), bufUsed - sizeof(*bin));
452     bufUsed += hdrDiff;
453     memcpy(buf, &outHeader, sizeof(outHeader));
454     memcpy(buf + sizeof(outHeader), &app, sizeof(app));
455     sect = &app.sect;
456 
457     //if we have any bytes to output, show stats
458     if (bufUsed) {
459         uint32_t codeAndRoDataSz = sect->data_data;
460         uint32_t relocsSz = sect->rel_end - sect->rel_start;
461         uint32_t gotSz = sect->got_end - sect->data_start;
462         uint32_t bssSz = sect->bss_end - sect->bss_start;
463 
464         fprintf(stderr,"Final binary size %" PRIu32 " bytes\n", bufUsed);
465         fprintf(stderr, "\n");
466         fprintf(stderr, "       FW header size (flash):      %6zu bytes\n", FLASH_RELOC_OFFSET);
467         fprintf(stderr, "       Code + RO data (flash):      %6" PRIu32 " bytes\n", codeAndRoDataSz);
468         fprintf(stderr, "       Relocs (flash):              %6" PRIu32 " bytes\n", relocsSz);
469         fprintf(stderr, "       GOT + RW data (flash & RAM): %6" PRIu32 " bytes\n", gotSz);
470         fprintf(stderr, "       BSS (RAM):                   %6" PRIu32 " bytes\n", bssSz);
471         fprintf(stderr, "\n");
472         fprintf(stderr,"Runtime flash use: %" PRIu32 " bytes\n", (uint32_t)(codeAndRoDataSz + relocsSz + gotSz + FLASH_RELOC_OFFSET));
473         fprintf(stderr,"Runtime RAM use: %" PRIu32 " bytes\n", gotSz + bssSz);
474     }
475 
476     ret = fwrite(buf, bufUsed, 1, out) == 1 ? 0 : 2;
477     if (ret)
478         fprintf(stderr, "Failed to write output file: %s\n", strerror(errno));
479 
480 out:
481     free(nanoRelocs);
482     return ret;
483 }
484 
handleKey(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,uint64_t appId,uint64_t keyId)485 static int handleKey(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint64_t keyId)
486 {
487     uint8_t *buf = *pbuf;
488     struct KeyInfo ki = { .data = keyId };
489     bool good = true;
490 
491     struct ImageHeader outHeader = {
492         .aosp = (struct nano_app_binary_t) {
493             .header_version = 1,
494             .magic = NANOAPP_AOSP_MAGIC,
495             .app_id = appId,
496         },
497         .layout = (struct ImageLayout) {
498             .magic = GOOGLE_LAYOUT_MAGIC,
499             .version = 1,
500             .payload = LAYOUT_KEY,
501             .flags = layoutFlags,
502         },
503     };
504 
505     good = good && fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
506     good = good && fwrite(&ki, sizeof(ki), 1, out) ==  1;
507     good = good && fwrite(buf, bufUsed, 1, out) == 1;
508 
509     return good ? 0 : 2;
510 }
511 
handleOs(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,bool bare)512 static int handleOs(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, bool bare)
513 {
514     uint8_t *buf = *pbuf;
515     bool good;
516 
517     struct OsUpdateHdr os = {
518         .magic = OS_UPDT_MAGIC,
519         .marker = OS_UPDT_MARKER_INPROGRESS,
520         .size = bufUsed
521     };
522 
523     struct ImageHeader outHeader = {
524         .aosp = (struct nano_app_binary_t) {
525             .header_version = 1,
526             .magic = NANOAPP_AOSP_MAGIC,
527         },
528         .layout = (struct ImageLayout) {
529             .magic = GOOGLE_LAYOUT_MAGIC,
530             .version = 1,
531             .payload = LAYOUT_OS,
532             .flags = layoutFlags,
533         },
534     };
535 
536     if (!bare)
537         good = fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
538     else
539         good = fwrite(&os, sizeof(os), 1, out) == 1;
540     good = good && fwrite(buf, bufUsed, 1, out) == 1;
541 
542     return good ? 0 : 2;
543 }
544 
main(int argc,char ** argv)545 int main(int argc, char **argv)
546 {
547     uint32_t bufUsed = 0;
548     bool verbose = false;
549     uint8_t *buf = NULL;
550     uint64_t appId = 0;
551     uint64_t keyId = 0;
552     uint32_t layoutId = 0;
553     uint32_t layoutFlags = 0;
554     int ret = -1;
555     uint32_t *u32Arg = NULL;
556     uint64_t *u64Arg = NULL;
557     const char **strArg = NULL;
558     const char *appName = argv[0];
559     int posArgCnt = 0;
560     const char *posArg[2] = { NULL };
561     FILE *out = NULL;
562     const char *layoutName = "app";
563     const char *prev = NULL;
564     bool bareData = false;
565 
566     for (int i = 1; i < argc; i++) {
567         char *end = NULL;
568         if (argv[i][0] == '-') {
569             prev = argv[i];
570             if (!strcmp(argv[i], "-v"))
571                 verbose = true;
572             else if (!strcmp(argv[i], "-r"))
573                 bareData = true;
574             else if (!strcmp(argv[i], "-a"))
575                 u64Arg = &appId;
576             else if (!strcmp(argv[i], "-k"))
577                 u64Arg = &keyId;
578             else if (!strcmp(argv[i], "-n"))
579                 strArg = &layoutName;
580             else if (!strcmp(argv[i], "-i"))
581                 u32Arg = &layoutId;
582             else if (!strcmp(argv[i], "-f"))
583                 u32Arg = &layoutFlags;
584             else
585                 fatalUsage(appName, "unknown argument", argv[i]);
586         } else {
587             if (u64Arg) {
588                 uint64_t tmp = strtoull(argv[i], &end, 16);
589                 if (*end == '\0')
590                     *u64Arg = tmp;
591                 u64Arg = NULL;
592             } else if (u32Arg) {
593                 uint32_t tmp = strtoul(argv[i], &end, 16);
594                 if (*end == '\0')
595                     *u32Arg = tmp;
596                 u32Arg = NULL;
597             } else if (strArg) {
598                     *strArg = argv[i];
599                 strArg = NULL;
600             } else {
601                 if (posArgCnt < 2)
602                     posArg[posArgCnt++] = argv[i];
603                 else
604                     fatalUsage(appName, "too many positional arguments", argv[i]);
605             }
606             prev = NULL;
607         }
608     }
609     if (prev)
610         fatalUsage(appName, "missing argument after", prev);
611 
612     if (!posArgCnt)
613         fatalUsage(appName, "missing input file name", NULL);
614 
615     if (!layoutId) {
616         if (strcmp(layoutName, "app") == 0)
617             layoutId = LAYOUT_APP;
618         else if (strcmp(layoutName, "os") == 0)
619             layoutId = LAYOUT_OS;
620         else if (strcmp(layoutName, "key") == 0)
621             layoutId = LAYOUT_KEY;
622         else
623             fatalUsage(appName, "Invalid layout name", layoutName);
624     }
625 
626     if (layoutId == LAYOUT_APP && !appId)
627         fatalUsage(appName, "App layout requires app ID", NULL);
628     if (layoutId == LAYOUT_KEY && !keyId)
629         fatalUsage(appName, "Key layout requires key ID", NULL);
630     if (layoutId == LAYOUT_OS && (keyId || appId))
631         fatalUsage(appName, "OS layout does not need any ID", NULL);
632 
633     buf = loadFile(posArg[0], &bufUsed);
634     fprintf(stderr, "Read %" PRIu32 " bytes\n", bufUsed);
635 
636     if (!posArg[1])
637         out = stdout;
638     else
639         out = fopen(posArg[1], "w");
640     if (!out)
641         fatalUsage(appName, "failed to create/open output file", posArg[1]);
642 
643     switch(layoutId) {
644     case LAYOUT_APP:
645         ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, verbose);
646         break;
647     case LAYOUT_KEY:
648         ret = handleKey(&buf, bufUsed, out, layoutFlags, appId, keyId);
649         break;
650     case LAYOUT_OS:
651         ret = handleOs(&buf, bufUsed, out, layoutFlags, bareData);
652         break;
653     }
654 
655     free(buf);
656     fclose(out);
657     return ret;
658 }
659