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