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
52struct 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
62struct SymtabEntry {
63    uint32_t a;
64    uint32_t addr;
65    uint32_t b, c;
66};
67
68struct NanoRelocEntry {
69    uint32_t ofstInRam;
70    uint8_t type;
71};
72
73struct 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
98static 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
103static 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
124bool 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
238static 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.
307static 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
333static 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
351static 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
403static 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);
567out:
568    free(app.nanoReloc);
569    free(app.packedNanoReloc);
570    return ret;
571}
572
573static 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
600static 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
633int 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