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 § 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