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 <gelf.h>
20 #include <libelf.h>
21 #include <sys/types.h>
22 #include <stdbool.h>
23 #include <unistd.h>
24 #include <stdlib.h>
25 #include <string.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stddef.h>
29 #include <errno.h>
30
31 #include <nanohub/nanohub.h>
32 #include <nanohub/nanoapp.h>
33 #include <nanohub/appRelocFormat.h>
34
35 //This code assumes it is run on a LE CPU with unaligned access abilities. Sorry.
36
37 #define FLASH_BASE 0x10000000
38 #define RAM_BASE 0x80000000
39
40 #define FLASH_SIZE 0x10000000 //256MB ought to be enough for everyone
41 #define RAM_SIZE 0x10000000 //256MB ought to be enough for everyone
42
43 //caution: double evaluation
44 #define IS_IN_RANGE_E(_val, _rstart, _rend) (((_val) >= (_rstart)) && ((_val) < (_rend)))
45 #define IS_IN_RANGE(_val, _rstart, _rsz) IS_IN_RANGE_E((_val), (_rstart), ((_rstart) + (_rsz)))
46 #define IS_IN_RAM(_val) IS_IN_RANGE(_val, RAM_BASE, RAM_SIZE)
47 #define IS_IN_FLASH(_val) IS_IN_RANGE(_val, FLASH_BASE, FLASH_SIZE)
48
49
50 #define NANO_RELOC_TYPE_RAM 0
51 #define NANO_RELOC_TYPE_FLASH 1
52 #define NANO_RELOC_LAST 2 //must be <= (RELOC_TYPE_MASK >> RELOC_TYPE_SHIFT)
53
54 struct RelocEntry {
55 uint32_t where;
56 uint32_t info; //bottom 8 bits is type, top 24 is sym idx
57 };
58
59 #define RELOC_TYPE_ABS_S 2
60 #define RELOC_TYPE_ABS_D 21
61 #define RELOC_TYPE_SECT 23
62
63
64 struct SymtabEntry {
65 uint32_t a;
66 uint32_t addr;
67 uint32_t b, c;
68 };
69
70 struct NanoRelocEntry {
71 uint32_t ofstInRam;
72 uint8_t type;
73 };
74
75 #ifndef ARRAY_SIZE
76 #define ARRAY_SIZE(ary) (sizeof(ary) / sizeof((ary)[0]))
77 #endif
78
79 #define DBG(fmt, ...) printf(fmt "\n", ##__VA_ARGS__)
80 #define ERR(fmt, ...) fprintf(stderr, fmt "\n", ##__VA_ARGS__)
81
82 // Prints the given message followed by the most recent libelf error
83 #define ELF_ERR(fmt, ...) ERR(fmt ": %s\n", ##__VA_ARGS__, elf_errmsg(-1))
84
85 struct ElfAppSection {
86 void *data;
87 size_t size;
88 };
89
90 struct ElfNanoApp {
91 struct ElfAppSection flash;
92 struct ElfAppSection data;
93 struct ElfAppSection relocs;
94 struct ElfAppSection symtab;
95
96 // Not parsed from file, but constructed via genElfNanoRelocs
97 struct ElfAppSection packedNanoRelocs;
98 };
99
fatalUsage(const char * name,const char * msg,const char * arg)100 static void fatalUsage(const char *name, const char *msg, const char *arg)
101 {
102 if (msg && arg)
103 fprintf(stderr, "Error: %s: %s\n\n", msg, arg);
104 else if (msg)
105 fprintf(stderr, "Error: %s\n\n", msg);
106
107 fprintf(stderr, "USAGE: %s [-v] [-k <key id>] [-a <app id>] [-r] [-n <layout name>] [-i <layout id>] <input file> [<output file>]\n"
108 " -v : be verbose\n"
109 " -n <layout name> : app, os, key\n"
110 " -i <layout id> : 1 (app), 2 (key), 3 (os)\n"
111 " -f <layout flags>: 16-bit hex value, stored as layout-specific flags\n"
112 " -a <app ID> : 64-bit hex number != 0\n"
113 " -e <app version> : 32-bit hex number\n"
114 " -k <key ID> : 64-bit hex number != 0\n"
115 " -r : bare (no AOSP header); used only for inner OS image generation\n"
116 " -s : treat input as statically linked ELF (app layout only)\n"
117 " layout ID and layout name control the same parameter, so only one of them needs to be used\n"
118 , name);
119 exit(1);
120 }
121
packNanoRelocs(struct NanoRelocEntry * nanoRelocs,uint32_t outNumRelocs,uint32_t * finalPackedNanoRelocSz,bool verbose)122 static uint8_t *packNanoRelocs(struct NanoRelocEntry *nanoRelocs, uint32_t outNumRelocs, uint32_t *finalPackedNanoRelocSz, bool verbose)
123 {
124 uint32_t i, j, k;
125 uint8_t *packedNanoRelocs;
126 uint32_t packedNanoRelocSz;
127 uint32_t lastOutType = 0, origin = 0;
128
129 //sort by type and then offset
130 for (i = 0; i < outNumRelocs; i++) {
131 struct NanoRelocEntry t;
132
133 for (k = i, j = k + 1; j < outNumRelocs; j++) {
134 if (nanoRelocs[j].type > nanoRelocs[k].type)
135 continue;
136 if ((nanoRelocs[j].type < nanoRelocs[k].type) || (nanoRelocs[j].ofstInRam < nanoRelocs[k].ofstInRam))
137 k = j;
138 }
139 memcpy(&t, nanoRelocs + i, sizeof(struct NanoRelocEntry));
140 memcpy(nanoRelocs + i, nanoRelocs + k, sizeof(struct NanoRelocEntry));
141 memcpy(nanoRelocs + k, &t, sizeof(struct NanoRelocEntry));
142
143 if (verbose)
144 fprintf(stderr, "SortedReloc[%3" PRIu32 "] = {0x%08" PRIX32 ",0x%02" PRIX8 "}\n", i, nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
145 }
146
147 //produce output nanorelocs in packed format
148 packedNanoRelocs = malloc(outNumRelocs * 6); //definitely big enough
149 packedNanoRelocSz = 0;
150 for (i = 0; i < outNumRelocs; i++) {
151 uint32_t displacement;
152
153 if (lastOutType != nanoRelocs[i].type) { //output type if ti changed
154 if (nanoRelocs[i].type - lastOutType == 1) {
155 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_NEXT;
156 if (verbose)
157 fprintf(stderr, "Out: RelocTC (1) // to 0x%02" PRIX8 "\n", nanoRelocs[i].type);
158 }
159 else {
160 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_RELOC_TYPE_CHG;
161 packedNanoRelocs[packedNanoRelocSz++] = nanoRelocs[i].type - lastOutType - 1;
162 if (verbose)
163 fprintf(stderr, "Out: RelocTC (0x%02" PRIX8 ") // to 0x%02" PRIX8 "\n", (uint8_t)(nanoRelocs[i].type - lastOutType - 1), nanoRelocs[i].type);
164 }
165 lastOutType = nanoRelocs[i].type;
166 origin = 0;
167 }
168 displacement = nanoRelocs[i].ofstInRam - origin;
169 origin = nanoRelocs[i].ofstInRam + 4;
170 if (displacement & 3) {
171 fprintf(stderr, "Unaligned relocs are not possible!\n");
172 exit(-5);
173 }
174 displacement /= 4;
175
176 //might be start of a run. look into that
177 if (!displacement) {
178 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++);
179 if (j >= MIN_RUN_LEN) {
180 if (verbose)
181 fprintf(stderr, "Out: Reloc0 x%" PRIX32 "\n", j);
182 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_CONSECUTIVE;
183 packedNanoRelocs[packedNanoRelocSz++] = j - MIN_RUN_LEN;
184 origin = nanoRelocs[j + i - 1].ofstInRam + 4; //reset origin to last one
185 i += j - 1; //loop will increment anyways, hence +1
186 continue;
187 }
188 }
189
190 //produce output
191 if (displacement <= MAX_8_BIT_NUM) {
192 if (verbose)
193 fprintf(stderr, "Out: Reloc8 0x%02" PRIX32 "\n", displacement);
194 packedNanoRelocs[packedNanoRelocSz++] = displacement;
195 }
196 else if (displacement <= MAX_16_BIT_NUM) {
197 if (verbose)
198 fprintf(stderr, "Out: Reloc16 0x%06" PRIX32 "\n", displacement);
199 displacement -= MAX_8_BIT_NUM;
200 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_16BIT_OFST;
201 packedNanoRelocs[packedNanoRelocSz++] = displacement;
202 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
203 }
204 else if (displacement <= MAX_24_BIT_NUM) {
205 if (verbose)
206 fprintf(stderr, "Out: Reloc24 0x%08" PRIX32 "\n", displacement);
207 displacement -= MAX_16_BIT_NUM;
208 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_24BIT_OFST;
209 packedNanoRelocs[packedNanoRelocSz++] = displacement;
210 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
211 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
212 }
213 else {
214 if (verbose)
215 fprintf(stderr, "Out: Reloc32 0x%08" PRIX32 "\n", displacement);
216 packedNanoRelocs[packedNanoRelocSz++] = TOKEN_32BIT_OFST;
217 packedNanoRelocs[packedNanoRelocSz++] = displacement;
218 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 8;
219 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 16;
220 packedNanoRelocs[packedNanoRelocSz++] = displacement >> 24;
221 }
222 }
223
224 *finalPackedNanoRelocSz = packedNanoRelocSz;
225 return packedNanoRelocs;
226 }
227
finalizeAndWrite(uint8_t * buf,uint32_t bufUsed,uint32_t bufSz,FILE * out,uint32_t layoutFlags,uint64_t appId)228 static int finalizeAndWrite(uint8_t *buf, uint32_t bufUsed, uint32_t bufSz, FILE *out, uint32_t layoutFlags, uint64_t appId)
229 {
230 int ret;
231 struct AppInfo app;
232 struct SectInfo *sect;
233 struct BinHdr *bin = (struct BinHdr *) buf;
234 struct ImageHeader outHeader = {
235 .aosp = (struct nano_app_binary_t) {
236 .header_version = 1,
237 .magic = NANOAPP_AOSP_MAGIC,
238 .app_id = appId,
239 .app_version = bin->hdr.appVer,
240 .flags = 0, // encrypted (1), signed (2) (will be set by other tools)
241 },
242 .layout = (struct ImageLayout) {
243 .magic = GOOGLE_LAYOUT_MAGIC,
244 .version = 1,
245 .payload = LAYOUT_APP,
246 .flags = layoutFlags,
247 },
248 };
249 uint32_t dataOffset = sizeof(outHeader) + sizeof(app);
250 uint32_t hdrDiff = dataOffset - sizeof(*bin);
251 app.sect = bin->sect;
252 app.vec = bin->vec;
253
254 assertMem(bufUsed + hdrDiff, bufSz);
255
256 memmove(buf + dataOffset, buf + sizeof(*bin), bufUsed - sizeof(*bin));
257 bufUsed += hdrDiff;
258 memcpy(buf, &outHeader, sizeof(outHeader));
259 memcpy(buf + sizeof(outHeader), &app, sizeof(app));
260 sect = &app.sect;
261
262 //if we have any bytes to output, show stats
263 if (bufUsed) {
264 uint32_t codeAndRoDataSz = sect->data_data;
265 uint32_t relocsSz = sect->rel_end - sect->rel_start;
266 uint32_t gotSz = sect->got_end - sect->data_start;
267 uint32_t bssSz = sect->bss_end - sect->bss_start;
268
269 fprintf(stderr,"Final binary size %" PRIu32 " bytes\n", bufUsed);
270 fprintf(stderr, "\n");
271 fprintf(stderr, " FW header size (flash): %6zu bytes\n", FLASH_RELOC_OFFSET);
272 fprintf(stderr, " Code + RO data (flash): %6" PRIu32 " bytes\n", codeAndRoDataSz);
273 fprintf(stderr, " Relocs (flash): %6" PRIu32 " bytes\n", relocsSz);
274 fprintf(stderr, " GOT + RW data (flash & RAM): %6" PRIu32 " bytes\n", gotSz);
275 fprintf(stderr, " BSS (RAM): %6" PRIu32 " bytes\n", bssSz);
276 fprintf(stderr, "\n");
277 fprintf(stderr,"Runtime flash use: %" PRIu32 " bytes\n", (uint32_t)(codeAndRoDataSz + relocsSz + gotSz + FLASH_RELOC_OFFSET));
278 fprintf(stderr,"Runtime RAM use: %" PRIu32 " bytes\n", gotSz + bssSz);
279 }
280
281 ret = fwrite(buf, bufUsed, 1, out) == 1 ? 0 : 2;
282 if (ret)
283 fprintf(stderr, "Failed to write output file: %s\n", strerror(errno));
284
285 return ret;
286 }
287
handleApp(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,uint64_t appId,uint32_t appVer,bool verbose)288 static int handleApp(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, bool verbose)
289 {
290 uint32_t i, numRelocs, numSyms, outNumRelocs = 0, packedNanoRelocSz;
291 struct NanoRelocEntry *nanoRelocs = NULL;
292 struct RelocEntry *relocs;
293 struct SymtabEntry *syms;
294 uint8_t *packedNanoRelocs;
295 uint32_t t;
296 struct BinHdr *bin;
297 int ret = -1;
298 struct SectInfo *sect;
299 uint8_t *buf = *pbuf;
300 uint32_t bufSz = bufUsed * 3 /2;
301
302 //make buffer 50% bigger than bufUsed in case relocs grow out of hand
303 buf = reallocOrDie(buf, bufSz);
304 *pbuf = buf;
305
306 //sanity checks
307 bin = (struct BinHdr*)buf;
308 if (bufUsed < sizeof(*bin)) {
309 fprintf(stderr, "File size too small\n");
310 goto out;
311 }
312
313 if (bin->hdr.magic != NANOAPP_FW_MAGIC) {
314 fprintf(stderr, "Magic value is wrong: found %08" PRIX32
315 "; expected %08" PRIX32 "\n",
316 bin->hdr.magic, NANOAPP_FW_MAGIC);
317 goto out;
318 }
319
320 sect = &bin->sect;
321 bin->hdr.appVer = appVer;
322
323 //do some math
324 relocs = (struct RelocEntry*)(buf + sect->rel_start - FLASH_BASE);
325 syms = (struct SymtabEntry*)(buf + sect->rel_end - FLASH_BASE);
326 numRelocs = (sect->rel_end - sect->rel_start) / sizeof(struct RelocEntry);
327 numSyms = (bufUsed + FLASH_BASE - sect->rel_end) / sizeof(struct SymtabEntry);
328
329 //sanity
330 if (numRelocs * sizeof(struct RelocEntry) + sect->rel_start != sect->rel_end) {
331 fprintf(stderr, "Relocs of nonstandard size\n");
332 goto out;
333 }
334 if (numSyms * sizeof(struct SymtabEntry) + sect->rel_end != bufUsed + FLASH_BASE) {
335 fprintf(stderr, "Syms of nonstandard size\n");
336 goto out;
337 }
338
339 //show some info
340 fprintf(stderr, "\nRead %" PRIu32 " bytes of binary.\n", bufUsed);
341
342 if (verbose)
343 fprintf(stderr, "Found %" PRIu32 " relocs and a %" PRIu32 "-entry symbol table\n", numRelocs, numSyms);
344
345 //handle relocs
346 nanoRelocs = malloc(sizeof(struct NanoRelocEntry[numRelocs]));
347 if (!nanoRelocs) {
348 fprintf(stderr, "Failed to allocate a nano-reloc table\n");
349 goto out;
350 }
351
352 for (i = 0; i < numRelocs; i++) {
353 uint32_t relocType = relocs[i].info & 0xff;
354 uint32_t whichSym = relocs[i].info >> 8;
355 uint32_t *valThereP;
356
357 if (whichSym >= numSyms) {
358 fprintf(stderr, "Reloc %" PRIu32 " references a nonexistent symbol!\n"
359 "INFO:\n"
360 " Where: 0x%08" PRIX32 "\n"
361 " type: %" PRIu32 "\n"
362 " sym: %" PRIu32 "\n",
363 i, relocs[i].where, relocs[i].info & 0xff, whichSym);
364 goto out;
365 }
366
367 if (verbose) {
368 const char *seg;
369
370 fprintf(stderr, "Reloc[%3" PRIu32 "]:\n {@0x%08" PRIX32 ", type %3" PRIu32 ", -> sym[%3" PRIu32 "]: {@0x%08" PRIX32 "}, ",
371 i, relocs[i].where, relocs[i].info & 0xff, whichSym, syms[whichSym].addr);
372
373 if (IS_IN_RANGE_E(relocs[i].where, sect->bss_start, sect->bss_end))
374 seg = ".bss";
375 else if (IS_IN_RANGE_E(relocs[i].where, sect->data_start, sect->data_end))
376 seg = ".data";
377 else if (IS_IN_RANGE_E(relocs[i].where, sect->got_start, sect->got_end))
378 seg = ".got";
379 else if (IS_IN_RANGE_E(relocs[i].where, FLASH_BASE, FLASH_BASE + sizeof(struct BinHdr)))
380 seg = "APPHDR";
381 else
382 seg = "???";
383
384 fprintf(stderr, "in %s}\n", seg);
385 }
386 /* handle relocs inside the header */
387 if (IS_IN_FLASH(relocs[i].where) && relocs[i].where - FLASH_BASE < sizeof(struct BinHdr) && relocType == RELOC_TYPE_SECT) {
388 /* relocs in header are special - runtime corrects for them */
389 if (syms[whichSym].addr) {
390 fprintf(stderr, "Weird in-header sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
391 i, whichSym, syms[whichSym].addr);
392 goto out;
393 }
394
395 valThereP = (uint32_t*)(buf + relocs[i].where - FLASH_BASE);
396 if (!IS_IN_FLASH(*valThereP)) {
397 fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of FLASH!\n"
398 "INFO:\n"
399 " type: %" PRIu32 "\n"
400 " sym: %" PRIu32 "\n"
401 " Sym Addr: 0x%08" PRIX32 "\n",
402 i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
403 goto out;
404 }
405
406 // binary header generated by objcopy, .napp header and final FW header in flash are of different size.
407 // we subtract binary header offset here, so all the entry points are relative to beginning of "sect".
408 // FW will use § as a base to call these vectors; no more problems with different header sizes;
409 // Assumption: offsets between sect & vec, vec & code are the same in all images (or, in a simpler words, { sect, vec, code }
410 // must go together). this is enforced by linker script, and maintained by all tools and FW download code in the OS.
411 *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
412
413 if (verbose)
414 fprintf(stderr, " -> Nano reloc skipped for in-header reloc\n");
415
416 continue; /* do not produce an output reloc */
417 }
418
419 if (!IS_IN_RAM(relocs[i].where)) {
420 fprintf(stderr, "In-header reloc %" PRIu32 " of location 0x%08" PRIX32 " is outside of RAM!\n"
421 "INFO:\n"
422 " type: %" PRIu32 "\n"
423 " sym: %" PRIu32 "\n"
424 " Sym Addr: 0x%08" PRIX32 "\n",
425 i, relocs[i].where, relocType, whichSym, syms[whichSym].addr);
426 goto out;
427 }
428
429 valThereP = (uint32_t*)(buf + relocs[i].where + sect->data_data - RAM_BASE - FLASH_BASE);
430
431 nanoRelocs[outNumRelocs].ofstInRam = relocs[i].where - RAM_BASE;
432
433 switch (relocType) {
434 case RELOC_TYPE_ABS_S:
435 case RELOC_TYPE_ABS_D:
436 t = *valThereP;
437
438 (*valThereP) += syms[whichSym].addr;
439
440 if (IS_IN_FLASH(syms[whichSym].addr)) {
441 (*valThereP) -= FLASH_BASE + BINARY_RELOC_OFFSET;
442 nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
443 }
444 else if (IS_IN_RAM(syms[whichSym].addr)) {
445 (*valThereP) -= RAM_BASE;
446 nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
447 }
448 else {
449 fprintf(stderr, "Weird reloc %" PRIu32 " to symbol %" PRIu32 " in unknown memory space (addr 0x%08" PRIX32 ")\n",
450 i, whichSym, syms[whichSym].addr);
451 goto out;
452 }
453 if (verbose)
454 fprintf(stderr, " -> Abs reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
455 break;
456
457 case RELOC_TYPE_SECT:
458 if (syms[whichSym].addr) {
459 fprintf(stderr, "Weird sect reloc %" PRIu32 " to symbol %" PRIu32 " with nonzero addr 0x%08" PRIX32 "\n",
460 i, whichSym, syms[whichSym].addr);
461 goto out;
462 }
463
464 t = *valThereP;
465
466 if (IS_IN_FLASH(*valThereP)) {
467 nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_FLASH;
468 *valThereP -= FLASH_BASE + BINARY_RELOC_OFFSET;
469 }
470 else if (IS_IN_RAM(*valThereP)) {
471 nanoRelocs[outNumRelocs].type = NANO_RELOC_TYPE_RAM;
472 *valThereP -= RAM_BASE;
473 }
474 else {
475 fprintf(stderr, "Weird sec reloc %" PRIu32 " to symbol %" PRIu32
476 " in unknown memory space (addr 0x%08" PRIX32 ")\n",
477 i, whichSym, *valThereP);
478 goto out;
479 }
480 if (verbose)
481 fprintf(stderr, " -> Sect reference fixed up 0x%08" PRIX32 " -> 0x%08" PRIX32 "\n", t, *valThereP);
482 break;
483
484 default:
485 fprintf(stderr, "Weird reloc %" PRIX32 " type %" PRIX32 " to symbol %" PRIX32 "\n", i, relocType, whichSym);
486 goto out;
487 }
488
489 if (verbose)
490 fprintf(stderr, " -> Nano reloc calculated as 0x%08" PRIX32 ",0x%02" PRIX8 "\n", nanoRelocs[i].ofstInRam, nanoRelocs[i].type);
491 outNumRelocs++;
492 }
493
494 packedNanoRelocs = packNanoRelocs(nanoRelocs, outNumRelocs, &packedNanoRelocSz, verbose);
495
496 //overwrite original relocs and symtab with nanorelocs and adjust sizes
497 memcpy(relocs, packedNanoRelocs, packedNanoRelocSz);
498 bufUsed -= sizeof(struct RelocEntry[numRelocs]);
499 bufUsed -= sizeof(struct SymtabEntry[numSyms]);
500 bufUsed += packedNanoRelocSz;
501 assertMem(bufUsed, bufSz);
502 sect->rel_end = sect->rel_start + packedNanoRelocSz;
503
504 //sanity
505 if (sect->rel_end - FLASH_BASE != bufUsed) {
506 fprintf(stderr, "Relocs end and file end not coincident\n");
507 goto out;
508 }
509
510 //adjust headers for easy access (RAM)
511 if (!IS_IN_RAM(sect->data_start) || !IS_IN_RAM(sect->data_end) || !IS_IN_RAM(sect->bss_start) ||
512 !IS_IN_RAM(sect->bss_end) || !IS_IN_RAM(sect->got_start) || !IS_IN_RAM(sect->got_end)) {
513 fprintf(stderr, "data, bss, or got not in ram\n");
514 goto out;
515 }
516 sect->data_start -= RAM_BASE;
517 sect->data_end -= RAM_BASE;
518 sect->bss_start -= RAM_BASE;
519 sect->bss_end -= RAM_BASE;
520 sect->got_start -= RAM_BASE;
521 sect->got_end -= RAM_BASE;
522
523 //adjust headers for easy access (FLASH)
524 if (!IS_IN_FLASH(sect->data_data) || !IS_IN_FLASH(sect->rel_start) || !IS_IN_FLASH(sect->rel_end)) {
525 fprintf(stderr, "data.data, or rel not in flash\n");
526 goto out;
527 }
528 sect->data_data -= FLASH_BASE + BINARY_RELOC_OFFSET;
529 sect->rel_start -= FLASH_BASE + BINARY_RELOC_OFFSET;
530 sect->rel_end -= FLASH_BASE + BINARY_RELOC_OFFSET;
531
532 ret = finalizeAndWrite(buf, bufUsed, bufSz, out, layoutFlags, appId);
533 out:
534 free(nanoRelocs);
535 return ret;
536 }
537
elfExtractSectionPointer(const Elf_Data * data,const char * name,struct ElfNanoApp * app)538 static void elfExtractSectionPointer(const Elf_Data *data, const char *name, struct ElfNanoApp *app)
539 {
540 // Maps section names to their byte offset in struct ElfNanoApp. Note that
541 // this assumes that the linker script puts text/code in the .flash section,
542 // RW data in .data, that relocs for .data are included in .rel.data, and
543 // the symbol table is emitted in .symtab
544 const struct SectionMap {
545 const char *name;
546 size_t offset;
547 } sectionMap[] = {
548 {
549 .name = ".flash",
550 .offset = offsetof(struct ElfNanoApp, flash),
551 },
552 {
553 .name = ".data",
554 .offset = offsetof(struct ElfNanoApp, data),
555 },
556 {
557 .name = ".rel.data",
558 .offset = offsetof(struct ElfNanoApp, relocs),
559 },
560 {
561 .name = ".symtab",
562 .offset = offsetof(struct ElfNanoApp, symtab),
563 },
564 };
565 struct ElfAppSection *appSection;
566 uint8_t *appBytes = (uint8_t *) app;
567
568 for (size_t i = 0; i < ARRAY_SIZE(sectionMap); i++) {
569 if (strcmp(name, sectionMap[i].name) != 0) {
570 continue;
571 }
572 appSection = (struct ElfAppSection *) &appBytes[sectionMap[i].offset];
573
574 appSection->data = data->d_buf;
575 appSection->size = data->d_size;
576
577 DBG("Found section %s with size %zu", name, appSection->size);
578 break;
579 }
580 }
581
582 // Populates a struct ElfNanoApp with data parsed from the ELF
elfParse(Elf * elf,struct ElfNanoApp * app)583 static bool elfParse(Elf *elf, struct ElfNanoApp *app)
584 {
585 size_t shdrstrndx;
586 Elf_Scn *scn = NULL;
587 GElf_Shdr shdr;
588 char *sectionName;
589 Elf_Data *elf_data;
590
591 memset(app, 0, sizeof(*app));
592 if (elf_getshdrstrndx(elf, &shdrstrndx) != 0) {
593 ELF_ERR("Couldn't get section name string table index");
594 return false;
595 }
596
597 while ((scn = elf_nextscn(elf, scn)) != NULL) {
598 if (gelf_getshdr(scn, &shdr) != &shdr) {
599 ELF_ERR("Error getting section header");
600 return false;
601 }
602 sectionName = elf_strptr(elf, shdrstrndx, shdr.sh_name);
603
604 elf_data = elf_getdata(scn, NULL);
605 if (!elf_data) {
606 ELF_ERR("Error getting data for section %s", sectionName);
607 return false;
608 }
609
610 elfExtractSectionPointer(elf_data, sectionName, app);
611 }
612
613 return true;
614 }
615
loadNanoappElfFile(const char * fileName,struct ElfNanoApp * app)616 static bool loadNanoappElfFile(const char *fileName, struct ElfNanoApp *app)
617 {
618 int fd;
619 Elf *elf;
620
621 if (elf_version(EV_CURRENT) == EV_NONE) {
622 ELF_ERR("Failed to initialize ELF library");
623 return false;
624 }
625
626 fd = open(fileName, O_RDONLY, 0);
627 if (fd < 0) {
628 ERR("Failed to open file %s for reading: %s", fileName, strerror(errno));
629 return false;
630 }
631
632 elf = elf_begin(fd, ELF_C_READ, NULL);
633 if (elf == NULL) {
634 ELF_ERR("Failed to open ELF");
635 return false;
636 }
637
638 if (!elfParse(elf, app)) {
639 ERR("Failed to parse ELF file");
640 return false;
641 }
642
643 return true;
644 }
645
646 // Subtracts the fixed memory region offset from an absolute address and returns
647 // the associated NANO_RELOC_* value, or NANO_RELOC_LAST if the address is not
648 // in the expected range.
649 // Not strictly tied to ELF usage, but handled slightly differently.
fixupAddrElf(uint32_t * addr)650 static uint8_t fixupAddrElf(uint32_t *addr)
651 {
652 uint8_t type;
653
654 // TODO: this assumes that the host running this tool has the same
655 // endianness as the image file/target processor
656 if (IS_IN_FLASH(*addr)) {
657 DBG("Fixup addr 0x%08" PRIX32 " (flash) --> 0x%08" PRIX32, *addr,
658 (uint32_t) (*addr - (FLASH_BASE + BINARY_RELOC_OFFSET)));
659 *addr -= FLASH_BASE + BINARY_RELOC_OFFSET;
660 type = NANO_RELOC_TYPE_FLASH;
661 } else if (IS_IN_RAM(*addr)) {
662 DBG("Fixup addr 0x%08" PRIX32 " (ram) --> 0x%08" PRIX32, *addr,
663 *addr - RAM_BASE);
664 *addr -= RAM_BASE;
665 type = NANO_RELOC_TYPE_RAM;
666 } else {
667 DBG("Error: invalid address 0x%08" PRIX32, *addr);
668 type = NANO_RELOC_LAST;
669 }
670
671 return type;
672 }
673
674 // Fixup addresses in the header to be relative. Not strictly tied to the ELF
675 // format, but used only in that program flow in the current implementation.
fixupHeaderElf(const struct ElfNanoApp * app)676 static bool fixupHeaderElf(const struct ElfNanoApp *app)
677 {
678 struct BinHdr *hdr = (struct BinHdr *) app->flash.data;
679
680 DBG("Appyling fixups to header");
681 if (fixupAddrElf(&hdr->sect.data_start) != NANO_RELOC_TYPE_RAM ||
682 fixupAddrElf(&hdr->sect.data_end) != NANO_RELOC_TYPE_RAM ||
683 fixupAddrElf(&hdr->sect.bss_start) != NANO_RELOC_TYPE_RAM ||
684 fixupAddrElf(&hdr->sect.bss_end) != NANO_RELOC_TYPE_RAM ||
685 fixupAddrElf(&hdr->sect.got_start) != NANO_RELOC_TYPE_RAM ||
686 fixupAddrElf(&hdr->sect.got_end) != NANO_RELOC_TYPE_RAM) {
687 ERR(".data, .bss, or .got not in RAM address space!");
688 return false;
689 }
690
691 if (fixupAddrElf(&hdr->sect.rel_start) != NANO_RELOC_TYPE_FLASH ||
692 fixupAddrElf(&hdr->sect.rel_end) != NANO_RELOC_TYPE_FLASH ||
693 fixupAddrElf(&hdr->sect.data_data) != NANO_RELOC_TYPE_FLASH) {
694 ERR(".data loadaddr, or .relocs not in flash address space!");
695 return false;
696 }
697
698 if (fixupAddrElf(&hdr->vec.init) != NANO_RELOC_TYPE_FLASH ||
699 fixupAddrElf(&hdr->vec.end) != NANO_RELOC_TYPE_FLASH ||
700 fixupAddrElf(&hdr->vec.handle) != NANO_RELOC_TYPE_FLASH) {
701 ERR("Entry point(s) not in flash address space!");
702 return false;
703 }
704
705 return true;
706 }
707
708 // Fixup addresses in .data, .init_array/.fini_array, and .got, and generates
709 // packed array of nano reloc entries. The app header must have already been
710 // fixed up.
genElfNanoRelocs(struct ElfNanoApp * app,bool verbose)711 static bool genElfNanoRelocs(struct ElfNanoApp *app, bool verbose)
712 {
713 const struct BinHdr *hdr = (const struct BinHdr *) app->flash.data;
714 const struct SectInfo *sect = &hdr->sect;
715 bool success = false;
716
717 size_t numDataRelocs = app->relocs.size / sizeof(Elf32_Rel);
718 size_t gotCount = (sect->got_end - sect->got_start) / sizeof(uint32_t);
719 size_t numInitFuncs = (sect->bss_start - sect->data_end) / sizeof(uint32_t);
720
721 size_t totalRelocCount = (numDataRelocs + numInitFuncs + gotCount);
722 struct NanoRelocEntry *nanoRelocs = malloc(
723 totalRelocCount * sizeof(struct NanoRelocEntry));
724 if (!nanoRelocs) {
725 ERR("Couldn't allocate memory for nano relocs! Needed %zu bytes",
726 totalRelocCount * sizeof(struct NanoRelocEntry));
727 return false;
728 }
729
730 uint8_t *data = app->data.data;
731 const Elf32_Rel *relocs = (const Elf32_Rel *) app->relocs.data;
732 const Elf32_Sym *syms = (const Elf32_Sym *) app->symtab.data;
733 size_t numRelocs = 0;
734
735 DBG("Parsing relocs for .data (%zu):", numDataRelocs);
736 for (size_t i = 0; i < numDataRelocs; i++) {
737 uint32_t type = ELF32_R_TYPE(relocs[i].r_info);
738 uint32_t sym = ELF32_R_SYM(relocs[i].r_info);
739
740 DBG(" [%3zu] 0x%08" PRIx32 " type %2" PRIu32 " symIdx %3" PRIu32
741 " --> 0x%08" PRIx32, i, relocs[i].r_offset, type, sym,
742 syms[sym].st_value);
743 // Note that R_ARM_TARGET1 is used for .init_array/.fini_array support,
744 // and can be interpreted either as ABS32 or REL32, depending on the
745 // runtime; we expect it to be ABS32.
746 if (type == R_ARM_ABS32 || type == R_ARM_TARGET1) {
747 if (!IS_IN_RAM(relocs[i].r_offset)) {
748 ERR("Reloc for .data not in RAM address range!");
749 goto out;
750 }
751 uint32_t offset = relocs[i].r_offset - RAM_BASE;
752 uint32_t *addr = (uint32_t *) &data[offset];
753
754 nanoRelocs[numRelocs].type = fixupAddrElf(addr);
755 nanoRelocs[numRelocs].ofstInRam = offset;
756 numRelocs++;
757 } else {
758 // TODO: Assuming that the ELF only contains absolute addresses in
759 // the .data section; may need to handle other relocation types in
760 // the future
761 ERR("Error: Unexpected reloc type %" PRIu32 " at index %zu",
762 type, i);
763 goto out;
764 }
765 }
766
767 DBG("Updating GOT entries (%zu):", gotCount);
768 for (uint32_t offset = sect->got_start; offset < sect->got_end;
769 offset += sizeof(uint32_t)) {
770 uint32_t *addr = (uint32_t *) &data[offset];
771 // Skip values that are set to 0, these seem to be padding (?)
772 if (*addr) {
773 nanoRelocs[numRelocs].type = fixupAddrElf(addr);
774 nanoRelocs[numRelocs].ofstInRam = offset;
775 numRelocs++;
776 }
777 }
778
779 uint32_t packedNanoRelocSz = 0;
780 app->packedNanoRelocs.data = packNanoRelocs(
781 nanoRelocs, numRelocs, &packedNanoRelocSz, verbose);
782 app->packedNanoRelocs.size = packedNanoRelocSz;
783 success = true;
784 out:
785 free(nanoRelocs);
786 return success;
787 }
788
handleAppStatic(const char * fileName,FILE * out,uint32_t layoutFlags,uint64_t appId,uint32_t appVer,bool verbose)789 static int handleAppStatic(const char *fileName, FILE *out, uint32_t layoutFlags, uint64_t appId, uint32_t appVer, bool verbose)
790 {
791 struct ElfNanoApp app;
792
793 if (!loadNanoappElfFile(fileName, &app)
794 || !fixupHeaderElf(&app)
795 || !genElfNanoRelocs(&app, verbose)) {
796 exit(2);
797 }
798
799 // Construct a single contiguous buffer, with extra room to fit the
800 // ImageHeader that will be prepended by finalizeAndWrite(). Note that this
801 // will allocate a bit more space than is needed, because some of the data
802 // from BinHdr will get discarded.
803 // TODO: this should be refactored to just write the binary components in
804 // order rather than allocating a big buffer, and moving data around
805 size_t bufSize = app.flash.size + app.data.size + app.packedNanoRelocs.size
806 + sizeof(struct ImageHeader);
807 uint8_t *buf = malloc(bufSize);
808 if (!buf) {
809 ERR("Failed to allocate %zu bytes for final app", bufSize);
810 exit(2);
811 }
812
813 size_t offset = 0;
814 memcpy(buf, app.flash.data, app.flash.size);
815 offset += app.flash.size;
816 memcpy(&buf[offset], app.data.data, app.data.size);
817 offset += app.data.size;
818 memcpy(&buf[offset], app.packedNanoRelocs.data, app.packedNanoRelocs.size);
819 offset += app.packedNanoRelocs.size;
820
821 // Update rel_end in the header to reflect the packed reloc size
822 struct BinHdr *hdr = (struct BinHdr *) buf;
823 hdr->sect.rel_end = hdr->sect.rel_start + app.packedNanoRelocs.size;
824 hdr->hdr.appVer = appVer;
825
826 return finalizeAndWrite(buf, offset, bufSize, out, layoutFlags, appId);
827 // TODO: should free all memory we allocated... just letting the OS handle
828 // it for now
829 }
830
handleKey(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,uint64_t appId,uint64_t keyId)831 static int handleKey(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, uint64_t appId, uint64_t keyId)
832 {
833 uint8_t *buf = *pbuf;
834 struct KeyInfo ki = { .data = keyId };
835 bool good = true;
836
837 struct ImageHeader outHeader = {
838 .aosp = (struct nano_app_binary_t) {
839 .header_version = 1,
840 .magic = NANOAPP_AOSP_MAGIC,
841 .app_id = appId,
842 },
843 .layout = (struct ImageLayout) {
844 .magic = GOOGLE_LAYOUT_MAGIC,
845 .version = 1,
846 .payload = LAYOUT_KEY,
847 .flags = layoutFlags,
848 },
849 };
850
851 good = good && fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
852 good = good && fwrite(&ki, sizeof(ki), 1, out) == 1;
853 good = good && fwrite(buf, bufUsed, 1, out) == 1;
854
855 return good ? 0 : 2;
856 }
857
handleOs(uint8_t ** pbuf,uint32_t bufUsed,FILE * out,uint32_t layoutFlags,bool bare)858 static int handleOs(uint8_t **pbuf, uint32_t bufUsed, FILE *out, uint32_t layoutFlags, bool bare)
859 {
860 uint8_t *buf = *pbuf;
861 bool good;
862
863 struct OsUpdateHdr os = {
864 .magic = OS_UPDT_MAGIC,
865 .marker = OS_UPDT_MARKER_INPROGRESS,
866 .size = bufUsed
867 };
868
869 struct ImageHeader outHeader = {
870 .aosp = (struct nano_app_binary_t) {
871 .header_version = 1,
872 .magic = NANOAPP_AOSP_MAGIC,
873 },
874 .layout = (struct ImageLayout) {
875 .magic = GOOGLE_LAYOUT_MAGIC,
876 .version = 1,
877 .payload = LAYOUT_OS,
878 .flags = layoutFlags,
879 },
880 };
881
882 if (!bare)
883 good = fwrite(&outHeader, sizeof(outHeader), 1, out) == 1;
884 else
885 good = fwrite(&os, sizeof(os), 1, out) == 1;
886 good = good && fwrite(buf, bufUsed, 1, out) == 1;
887
888 return good ? 0 : 2;
889 }
890
main(int argc,char ** argv)891 int main(int argc, char **argv)
892 {
893 uint32_t bufUsed = 0;
894 bool verbose = false;
895 uint8_t *buf = NULL;
896 uint64_t appId = 0;
897 uint64_t keyId = 0;
898 uint32_t appVer = 0;
899 uint32_t layoutId = 0;
900 uint32_t layoutFlags = 0;
901 int ret = -1;
902 uint32_t *u32Arg = NULL;
903 uint64_t *u64Arg = NULL;
904 const char **strArg = NULL;
905 const char *appName = argv[0];
906 int posArgCnt = 0;
907 const char *posArg[2] = { NULL };
908 FILE *out = NULL;
909 const char *layoutName = "app";
910 const char *prev = NULL;
911 bool bareData = false;
912 bool staticElf = false;
913
914 for (int i = 1; i < argc; i++) {
915 char *end = NULL;
916 if (argv[i][0] == '-') {
917 prev = argv[i];
918 if (!strcmp(argv[i], "-v"))
919 verbose = true;
920 else if (!strcmp(argv[i], "-r"))
921 bareData = true;
922 else if (!strcmp(argv[i], "-s"))
923 staticElf = true;
924 else if (!strcmp(argv[i], "-a"))
925 u64Arg = &appId;
926 else if (!strcmp(argv[i], "-e"))
927 u32Arg = &appVer;
928 else if (!strcmp(argv[i], "-k"))
929 u64Arg = &keyId;
930 else if (!strcmp(argv[i], "-n"))
931 strArg = &layoutName;
932 else if (!strcmp(argv[i], "-i"))
933 u32Arg = &layoutId;
934 else if (!strcmp(argv[i], "-f"))
935 u32Arg = &layoutFlags;
936 else
937 fatalUsage(appName, "unknown argument", argv[i]);
938 } else {
939 if (u64Arg) {
940 uint64_t tmp = strtoull(argv[i], &end, 16);
941 if (*end == '\0')
942 *u64Arg = tmp;
943 u64Arg = NULL;
944 } else if (u32Arg) {
945 uint32_t tmp = strtoul(argv[i], &end, 16);
946 if (*end == '\0')
947 *u32Arg = tmp;
948 u32Arg = NULL;
949 } else if (strArg) {
950 *strArg = argv[i];
951 strArg = NULL;
952 } else {
953 if (posArgCnt < 2)
954 posArg[posArgCnt++] = argv[i];
955 else
956 fatalUsage(appName, "too many positional arguments", argv[i]);
957 }
958 prev = NULL;
959 }
960 }
961 if (prev)
962 fatalUsage(appName, "missing argument after", prev);
963
964 if (!posArgCnt)
965 fatalUsage(appName, "missing input file name", NULL);
966
967 if (!layoutId) {
968 if (strcmp(layoutName, "app") == 0)
969 layoutId = LAYOUT_APP;
970 else if (strcmp(layoutName, "os") == 0)
971 layoutId = LAYOUT_OS;
972 else if (strcmp(layoutName, "key") == 0)
973 layoutId = LAYOUT_KEY;
974 else
975 fatalUsage(appName, "Invalid layout name", layoutName);
976 }
977
978 if (staticElf && layoutId != LAYOUT_APP)
979 fatalUsage(appName, "Only app layout is supported for static option", NULL);
980
981 if (layoutId == LAYOUT_APP && !appId)
982 fatalUsage(appName, "App layout requires app ID", NULL);
983 if (layoutId == LAYOUT_KEY && !keyId)
984 fatalUsage(appName, "Key layout requires key ID", NULL);
985 if (layoutId == LAYOUT_OS && (keyId || appId))
986 fatalUsage(appName, "OS layout does not need any ID", NULL);
987
988 if (!staticElf) {
989 buf = loadFile(posArg[0], &bufUsed);
990 fprintf(stderr, "Read %" PRIu32 " bytes\n", bufUsed);
991 }
992
993 if (!posArg[1])
994 out = stdout;
995 else
996 out = fopen(posArg[1], "w");
997 if (!out)
998 fatalUsage(appName, "failed to create/open output file", posArg[1]);
999
1000 switch(layoutId) {
1001 case LAYOUT_APP:
1002 if (staticElf) {
1003 ret = handleAppStatic(posArg[0], out, layoutFlags, appId, appVer, verbose);
1004 } else {
1005 ret = handleApp(&buf, bufUsed, out, layoutFlags, appId, appVer, verbose);
1006 }
1007 break;
1008 case LAYOUT_KEY:
1009 ret = handleKey(&buf, bufUsed, out, layoutFlags, appId, keyId);
1010 break;
1011 case LAYOUT_OS:
1012 ret = handleOs(&buf, bufUsed, out, layoutFlags, bareData);
1013 break;
1014 }
1015
1016 free(buf);
1017 fclose(out);
1018 return ret;
1019 }
1020