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