mkfwimage.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. // SPDX-License-Identifier: GPL-2.0-or-later
  2. /*
  3. * Copyright (C) 2007 Ubiquiti Networks, Inc.
  4. * Copyright (C) 2008 Lukas Kuna <[email protected]>
  5. */
  6. #include <sys/types.h>
  7. #include <sys/stat.h>
  8. #include <inttypes.h>
  9. #include <fcntl.h>
  10. #include <unistd.h>
  11. #include <string.h>
  12. #include <errno.h>
  13. #include <zlib.h>
  14. #include <sys/mman.h>
  15. #include <netinet/in.h>
  16. #include <stdio.h>
  17. #include <stdlib.h>
  18. #include <limits.h>
  19. #include <stdbool.h>
  20. #include "fw.h"
  21. #include "utils.h"
  22. typedef struct fw_layout_data {
  23. u_int32_t kern_start;
  24. u_int32_t kern_entry;
  25. u_int32_t firmware_max_length;
  26. } fw_layout_t;
  27. struct fw_info {
  28. char name[PATH_MAX];
  29. struct fw_layout_data fw_layout;
  30. bool sign;
  31. };
  32. struct fw_info fw_info[] = {
  33. {
  34. .name = "XS2",
  35. .fw_layout = {
  36. .kern_start = 0xbfc30000,
  37. .kern_entry = 0x80041000,
  38. .firmware_max_length= 0x00390000,
  39. },
  40. .sign = false,
  41. },
  42. {
  43. .name = "XS5",
  44. .fw_layout = {
  45. .kern_start = 0xbe030000,
  46. .kern_entry = 0x80041000,
  47. .firmware_max_length= 0x00390000,
  48. },
  49. .sign = false,
  50. },
  51. {
  52. .name = "RS",
  53. .fw_layout = {
  54. .kern_start = 0xbf030000,
  55. .kern_entry = 0x80060000,
  56. .firmware_max_length= 0x00B00000,
  57. },
  58. .sign = false,
  59. },
  60. {
  61. .name = "RSPRO",
  62. .fw_layout = {
  63. .kern_start = 0xbf030000,
  64. .kern_entry = 0x80060000,
  65. .firmware_max_length= 0x00F00000,
  66. },
  67. .sign = false,
  68. },
  69. {
  70. .name = "LS-SR71",
  71. .fw_layout = {
  72. .kern_start = 0xbf030000,
  73. .kern_entry = 0x80060000,
  74. .firmware_max_length= 0x00640000,
  75. },
  76. .sign = false,
  77. },
  78. {
  79. .name = "XS2-8",
  80. .fw_layout = {
  81. .kern_start = 0xa8030000,
  82. .kern_entry = 0x80041000,
  83. .firmware_max_length= 0x006C0000,
  84. },
  85. .sign = false,
  86. },
  87. {
  88. .name = "XM",
  89. .fw_layout = {
  90. .kern_start = 0x9f050000,
  91. .kern_entry = 0x80002000,
  92. .firmware_max_length= 0x00760000,
  93. },
  94. .sign = false,
  95. },
  96. {
  97. .name = "SW",
  98. .fw_layout = {
  99. .kern_start = 0x9f050000,
  100. .kern_entry = 0x80002000,
  101. .firmware_max_length= 0x00760000,
  102. },
  103. .sign = false,
  104. },
  105. {
  106. .name = "UBDEV01",
  107. .fw_layout = {
  108. .kern_start = 0x9f050000,
  109. .kern_entry = 0x80002000,
  110. .firmware_max_length= 0x006A0000,
  111. },
  112. .sign = false,
  113. },
  114. {
  115. .name = "WA",
  116. .fw_layout = {
  117. .kern_start = 0x9f050000,
  118. .kern_entry = 0x80002000,
  119. .firmware_max_length= 0x00F60000,
  120. },
  121. .sign = true,
  122. },
  123. {
  124. .name = "XC",
  125. .fw_layout = {
  126. .kern_start = 0x9f050000,
  127. .kern_entry = 0x80002000,
  128. .firmware_max_length= 0x00F60000,
  129. },
  130. .sign = true,
  131. },
  132. {
  133. .name = "ACB",
  134. .fw_layout = {
  135. .kern_start = 0x9f050000,
  136. .kern_entry = 0x80002000,
  137. .firmware_max_length= 0x00F60000,
  138. },
  139. .sign = true,
  140. },
  141. {
  142. .name = "",
  143. },
  144. };
  145. typedef struct part_data {
  146. char partition_name[64];
  147. int partition_index;
  148. u_int32_t partition_baseaddr;
  149. u_int32_t partition_startaddr;
  150. u_int32_t partition_memaddr;
  151. u_int32_t partition_entryaddr;
  152. u_int32_t partition_length;
  153. char filename[PATH_MAX];
  154. struct stat stats;
  155. } part_data_t;
  156. #define MAX_SECTIONS 8
  157. #define DEFAULT_OUTPUT_FILE "firmware-image.bin"
  158. #define DEFAULT_VERSION "UNKNOWN"
  159. #define OPTIONS "B:hv:m:o:r:k:"
  160. typedef struct image_info {
  161. char magic[16];
  162. char version[256];
  163. char outputfile[PATH_MAX];
  164. u_int32_t part_count;
  165. part_data_t parts[MAX_SECTIONS];
  166. struct fw_info* fwinfo;
  167. } image_info_t;
  168. static struct fw_info* get_fwinfo(char* board_name) {
  169. struct fw_info *fwinfo = fw_info;
  170. while(strlen(fwinfo->name)) {
  171. if(strcmp(fwinfo->name, board_name) == 0) {
  172. return fwinfo;
  173. }
  174. fwinfo++;
  175. }
  176. return NULL;
  177. }
  178. static void write_header(void* mem, const char *magic, const char* version)
  179. {
  180. header_t* header = mem;
  181. memset(header, 0, sizeof(header_t));
  182. FW_MEMCPY_STR(header->magic, magic);
  183. FW_MEMCPY_STR(header->version, version);
  184. header->crc = htonl(crc32(0L, (uint8_t*) header,
  185. sizeof(header_t) - 2 * sizeof(u_int32_t)));
  186. header->pad = 0L;
  187. }
  188. static void write_signature(void* mem, u_int32_t sig_offset)
  189. {
  190. /* write signature */
  191. signature_t* sign = (signature_t*)(mem + sig_offset);
  192. memset(sign, 0, sizeof(signature_t));
  193. FW_MEMCPY_STR(sign->magic, MAGIC_END);
  194. sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
  195. sign->pad = 0L;
  196. }
  197. static void write_signature_rsa(void* mem, u_int32_t sig_offset)
  198. {
  199. /* write signature */
  200. signature_rsa_t* sign = (signature_rsa_t*)(mem + sig_offset);
  201. memset(sign, 0, sizeof(signature_rsa_t));
  202. FW_MEMCPY_STR(sign->magic, MAGIC_ENDS);
  203. // sign->crc = htonl(crc32(0L,(unsigned char *)mem, sig_offset));
  204. sign->pad = 0L;
  205. }
  206. static int write_part(void* mem, part_data_t* d)
  207. {
  208. char* addr;
  209. int fd;
  210. part_t* p = mem;
  211. part_crc_t* crc = mem + sizeof(part_t) + d->stats.st_size;
  212. fd = open(d->filename, O_RDONLY);
  213. if (fd < 0)
  214. {
  215. ERROR("Failed opening file '%s'\n", d->filename);
  216. return -1;
  217. }
  218. if ((addr=(char*)mmap(0, d->stats.st_size, PROT_READ, MAP_SHARED, fd, 0)) == MAP_FAILED)
  219. {
  220. ERROR("Failed mmaping memory for file '%s'\n", d->filename);
  221. close(fd);
  222. return -2;
  223. }
  224. memcpy(mem + sizeof(part_t), addr, d->stats.st_size);
  225. munmap(addr, d->stats.st_size);
  226. memset(p->name, 0, PART_NAME_LENGTH);
  227. FW_MEMCPY_STR(p->magic, MAGIC_PART);
  228. FW_MEMCPY_STR(p->name, d->partition_name);
  229. p->index = htonl(d->partition_index);
  230. p->data_size = htonl(d->stats.st_size);
  231. p->part_size = htonl(d->partition_length);
  232. p->baseaddr = htonl(d->partition_baseaddr);
  233. p->memaddr = htonl(d->partition_memaddr);
  234. p->entryaddr = htonl(d->partition_entryaddr);
  235. crc->crc = htonl(crc32(0L, mem, d->stats.st_size + sizeof(part_t)));
  236. crc->pad = 0L;
  237. return 0;
  238. }
  239. static void usage(const char* progname)
  240. {
  241. INFO("Version %s\n"
  242. "Usage: %s [options]\n"
  243. "\t-v <version string>\t - firmware version information, default: %s\n"
  244. "\t-o <output file>\t - firmware output file, default: %s\n"
  245. "\t-m <magic>\t - firmware magic, default: %s\n"
  246. "\t-k <kernel file>\t\t - kernel file\n"
  247. "\t-r <rootfs file>\t\t - rootfs file\n"
  248. "\t-B <board name>\t\t - choose firmware layout for specified board (XS2, XS5, RS, XM)\n"
  249. "\t-h\t\t\t - this help\n", VERSION,
  250. progname, DEFAULT_VERSION, DEFAULT_OUTPUT_FILE, MAGIC_HEADER);
  251. }
  252. static void print_image_info(const image_info_t* im)
  253. {
  254. unsigned int i = 0;
  255. INFO("Firmware version: '%s'\n"
  256. "Output file: '%s'\n"
  257. "Part count: %u\n",
  258. im->version, im->outputfile,
  259. im->part_count);
  260. for (i = 0; i < im->part_count; ++i)
  261. {
  262. const part_data_t* d = &im->parts[i];
  263. INFO(" %10s: %8" PRId64 " bytes (free: %8" PRId64 ")\n",
  264. d->partition_name,
  265. d->stats.st_size,
  266. d->partition_length - d->stats.st_size);
  267. }
  268. }
  269. static u_int32_t filelength(const char* file)
  270. {
  271. FILE *p;
  272. int ret = -1;
  273. if ( (p = fopen(file, "rb") ) == NULL) return (-1);
  274. fseek(p, 0, SEEK_END);
  275. ret = ftell(p);
  276. fclose (p);
  277. return (ret);
  278. }
  279. static int create_image_layout(const char* kernelfile, const char* rootfsfile, image_info_t* im)
  280. {
  281. uint32_t rootfs_len = 0;
  282. part_data_t* kernel = &im->parts[0];
  283. part_data_t* rootfs = &im->parts[1];
  284. fw_layout_t* p = &im->fwinfo->fw_layout;
  285. printf("board = %s\n", im->fwinfo->name);
  286. strcpy(kernel->partition_name, "kernel");
  287. kernel->partition_index = 1;
  288. kernel->partition_baseaddr = p->kern_start;
  289. if ( (kernel->partition_length = filelength(kernelfile)) == (u_int32_t)-1) return (-1);
  290. kernel->partition_memaddr = p->kern_entry;
  291. kernel->partition_entryaddr = p->kern_entry;
  292. strncpy(kernel->filename, kernelfile, sizeof(kernel->filename));
  293. rootfs_len = filelength(rootfsfile);
  294. if (rootfs_len + kernel->partition_length > p->firmware_max_length) {
  295. ERROR("File '%s' too big (0x%08X) - max size: 0x%08X (exceeds %u bytes)\n",
  296. rootfsfile, rootfs_len, p->firmware_max_length,
  297. (rootfs_len + kernel->partition_length) - p->firmware_max_length);
  298. return (-2);
  299. }
  300. strcpy(rootfs->partition_name, "rootfs");
  301. rootfs->partition_index = 2;
  302. rootfs->partition_baseaddr = kernel->partition_baseaddr + kernel->partition_length;
  303. rootfs->partition_length = p->firmware_max_length - kernel->partition_length;
  304. rootfs->partition_memaddr = 0x00000000;
  305. rootfs->partition_entryaddr = 0x00000000;
  306. strncpy(rootfs->filename, rootfsfile, sizeof(rootfs->filename));
  307. printf("kernel: %d 0x%08x\n", kernel->partition_length, kernel->partition_baseaddr);
  308. printf("root: %d 0x%08x\n", rootfs->partition_length, rootfs->partition_baseaddr);
  309. im->part_count = 2;
  310. return 0;
  311. }
  312. /**
  313. * Checks the availability and validity of all image components.
  314. * Fills in stats member of the part_data structure.
  315. */
  316. static int validate_image_layout(image_info_t* im)
  317. {
  318. unsigned int i;
  319. if (im->part_count == 0 || im->part_count > MAX_SECTIONS)
  320. {
  321. ERROR("Invalid part count '%d'\n", im->part_count);
  322. return -1;
  323. }
  324. for (i = 0; i < im->part_count; ++i)
  325. {
  326. part_data_t* d = &im->parts[i];
  327. int len = strlen(d->partition_name);
  328. if (len == 0 || len > 16)
  329. {
  330. ERROR("Invalid partition name '%s' of the part %d\n",
  331. d->partition_name, i);
  332. return -1;
  333. }
  334. if (stat(d->filename, &d->stats) < 0)
  335. {
  336. ERROR("Couldn't stat file '%s' from part '%s'\n",
  337. d->filename, d->partition_name);
  338. return -2;
  339. }
  340. if (d->stats.st_size == 0)
  341. {
  342. ERROR("File '%s' from part '%s' is empty!\n",
  343. d->filename, d->partition_name);
  344. return -3;
  345. }
  346. if (d->stats.st_size > d->partition_length) {
  347. ERROR("File '%s' too big (%d) - max size: 0x%08X (exceeds %" PRId64 " bytes)\n",
  348. d->filename, i, d->partition_length,
  349. d->stats.st_size - d->partition_length);
  350. return -4;
  351. }
  352. }
  353. return 0;
  354. }
  355. static int build_image(image_info_t* im)
  356. {
  357. char* mem;
  358. char* ptr;
  359. u_int32_t mem_size;
  360. FILE* f;
  361. unsigned int i;
  362. // build in-memory buffer
  363. mem_size = sizeof(header_t);
  364. if(im->fwinfo->sign) {
  365. mem_size += sizeof(signature_rsa_t);
  366. } else {
  367. mem_size += sizeof(signature_t);
  368. }
  369. for (i = 0; i < im->part_count; ++i)
  370. {
  371. part_data_t* d = &im->parts[i];
  372. mem_size += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
  373. }
  374. mem = (char*)calloc(mem_size, 1);
  375. if (mem == NULL)
  376. {
  377. ERROR("Cannot allocate memory chunk of size '%u'\n", mem_size);
  378. return -1;
  379. }
  380. // write header
  381. write_header(mem, im->magic, im->version);
  382. ptr = mem + sizeof(header_t);
  383. // write all parts
  384. for (i = 0; i < im->part_count; ++i)
  385. {
  386. part_data_t* d = &im->parts[i];
  387. int rc;
  388. if ((rc = write_part(ptr, d)) != 0)
  389. {
  390. ERROR("ERROR: failed writing part %u '%s'\n", i, d->partition_name);
  391. }
  392. ptr += sizeof(part_t) + d->stats.st_size + sizeof(part_crc_t);
  393. }
  394. // write signature
  395. if(im->fwinfo->sign) {
  396. write_signature_rsa(mem, mem_size - sizeof(signature_rsa_t));
  397. } else {
  398. write_signature(mem, mem_size - sizeof(signature_t));
  399. }
  400. // write in-memory buffer into file
  401. if ((f = fopen(im->outputfile, "w")) == NULL)
  402. {
  403. ERROR("Can not create output file: '%s'\n", im->outputfile);
  404. free(mem);
  405. return -10;
  406. }
  407. if (fwrite(mem, mem_size, 1, f) != 1)
  408. {
  409. ERROR("Could not write %d bytes into file: '%s'\n",
  410. mem_size, im->outputfile);
  411. free(mem);
  412. fclose(f);
  413. return -11;
  414. }
  415. free(mem);
  416. fclose(f);
  417. return 0;
  418. }
  419. int main(int argc, char* argv[])
  420. {
  421. char kernelfile[PATH_MAX];
  422. char rootfsfile[PATH_MAX];
  423. char board_name[PATH_MAX];
  424. int o, rc;
  425. image_info_t im;
  426. struct fw_info *fwinfo;
  427. memset(&im, 0, sizeof(im));
  428. memset(kernelfile, 0, sizeof(kernelfile));
  429. memset(rootfsfile, 0, sizeof(rootfsfile));
  430. memset(board_name, 0, sizeof(board_name));
  431. strcpy(im.outputfile, DEFAULT_OUTPUT_FILE);
  432. strcpy(im.version, DEFAULT_VERSION);
  433. strncpy(im.magic, MAGIC_HEADER, sizeof(im.magic));
  434. while ((o = getopt(argc, argv, OPTIONS)) != -1)
  435. {
  436. switch (o) {
  437. case 'v':
  438. if (optarg)
  439. strncpy(im.version, optarg, sizeof(im.version) - 1);
  440. break;
  441. case 'o':
  442. if (optarg)
  443. strncpy(im.outputfile, optarg, sizeof(im.outputfile) - 1);
  444. break;
  445. case 'm':
  446. if (optarg)
  447. strncpy(im.magic, optarg, sizeof(im.magic) - 1);
  448. break;
  449. case 'h':
  450. usage(argv[0]);
  451. return -1;
  452. case 'k':
  453. if (optarg)
  454. strncpy(kernelfile, optarg, sizeof(kernelfile) - 1);
  455. break;
  456. case 'r':
  457. if (optarg)
  458. strncpy(rootfsfile, optarg, sizeof(rootfsfile) - 1);
  459. break;
  460. case 'B':
  461. if (optarg)
  462. strncpy(board_name, optarg, sizeof(board_name) - 1);
  463. break;
  464. }
  465. }
  466. if (strlen(board_name) == 0)
  467. strcpy(board_name, "XS2"); /* default to XS2 */
  468. if (strlen(kernelfile) == 0)
  469. {
  470. ERROR("Kernel file is not specified, cannot continue\n");
  471. usage(argv[0]);
  472. return -2;
  473. }
  474. if (strlen(rootfsfile) == 0)
  475. {
  476. ERROR("Root FS file is not specified, cannot continue\n");
  477. usage(argv[0]);
  478. return -2;
  479. }
  480. if ((fwinfo = get_fwinfo(board_name)) == NULL) {
  481. ERROR("Invalid baord name '%s'\n", board_name);
  482. usage(argv[0]);
  483. return -2;
  484. }
  485. im.fwinfo = fwinfo;
  486. if ((rc = create_image_layout(kernelfile, rootfsfile, &im)) != 0)
  487. {
  488. ERROR("Failed creating firmware layout description - error code: %d\n", rc);
  489. return -3;
  490. }
  491. if ((rc = validate_image_layout(&im)) != 0)
  492. {
  493. ERROR("Failed validating firmware layout - error code: %d\n", rc);
  494. return -4;
  495. }
  496. print_image_info(&im);
  497. if ((rc = build_image(&im)) != 0)
  498. {
  499. ERROR("Failed building image file '%s' - error code: %d\n", im.outputfile, rc);
  500. return -5;
  501. }
  502. return 0;
  503. }