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