update_octeon_header.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456
  1. // SPDX-License-Identifier: GPL-2.0
  2. /*
  3. * Copyright (C) 2020 Marvell International Ltd.
  4. */
  5. #include <stdio.h>
  6. #include <stdint.h>
  7. #include <stddef.h>
  8. #include <sys/types.h>
  9. #include <sys/stat.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <stdbool.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <getopt.h>
  16. #include <arpa/inet.h>
  17. #include <linux/compiler.h>
  18. #include <u-boot/crc.h>
  19. #include "mkimage.h"
  20. #include "../arch/mips/mach-octeon/include/mach/cvmx-bootloader.h"
  21. #define BUF_SIZE (16 * 1024)
  22. #define NAME_LEN 100
  23. /* word offset */
  24. #define WOFFSETOF(type, elem) (offsetof(type, elem) / 4)
  25. static int stage2_flag;
  26. static int stage_1_5_flag;
  27. static int stage_1_flag;
  28. /* Getoptions variables must be global */
  29. static int failsafe_flag;
  30. static int pciboot_flag;
  31. static int env_flag;
  32. static const struct option long_options[] = {
  33. /* These options set a flag. */
  34. {"failsafe", no_argument, &failsafe_flag, 1},
  35. {"pciboot", no_argument, &pciboot_flag, 1},
  36. {"nandstage2", no_argument, &stage2_flag, 1},
  37. {"spistage2", no_argument, &stage2_flag, 1},
  38. {"norstage2", no_argument, &stage2_flag, 1},
  39. {"stage2", no_argument, &stage2_flag, 1},
  40. {"stage1.5", no_argument, &stage_1_5_flag, 1},
  41. {"stage1", no_argument, &stage_1_flag, 1},
  42. {"environment", no_argument, &env_flag, 1},
  43. /*
  44. * These options don't set a flag.
  45. * We distinguish them by their indices.
  46. */
  47. {"board", required_argument, 0, 0},
  48. {"text_base", required_argument, 0, 0},
  49. {0, 0, 0, 0}
  50. };
  51. static int lookup_board_type(char *board_name)
  52. {
  53. int i;
  54. int board_type = 0;
  55. char *substr = NULL;
  56. /* Detect stage 2 bootloader boards */
  57. if (strcasestr(board_name, "_stage2")) {
  58. printf("Stage 2 bootloader detected from substring %s in name %s\n",
  59. "_stage2", board_name);
  60. stage2_flag = 1;
  61. } else {
  62. printf("Stage 2 bootloader NOT detected from name \"%s\"\n",
  63. board_name);
  64. }
  65. if (strcasestr(board_name, "_stage1")) {
  66. printf("Stage 1 bootloader detected from substring %s in name %s\n",
  67. "_stage1", board_name);
  68. stage_1_flag = 1;
  69. }
  70. /* Generic is a special case since there are numerous sub-types */
  71. if (!strncasecmp("generic", board_name, strlen("generic")))
  72. return CVMX_BOARD_TYPE_GENERIC;
  73. /*
  74. * If we're an eMMC stage 2 bootloader, cut off the _emmc_stage2
  75. * part of the name.
  76. */
  77. substr = strcasestr(board_name, "_emmc_stage2");
  78. if (substr && (substr[strlen("_emmc_stage2")] == '\0')) {
  79. /*return CVMX_BOARD_TYPE_GENERIC;*/
  80. printf(" Converting board name %s to ", board_name);
  81. *substr = '\0';
  82. printf("%s\n", board_name);
  83. }
  84. /*
  85. * If we're a NAND stage 2 bootloader, cut off the _nand_stage2
  86. * part of the name.
  87. */
  88. substr = strcasestr(board_name, "_nand_stage2");
  89. if (substr && (substr[strlen("_nand_stage2")] == '\0')) {
  90. /*return CVMX_BOARD_TYPE_GENERIC;*/
  91. printf(" Converting board name %s to ", board_name);
  92. *substr = '\0';
  93. printf("%s\n", board_name);
  94. }
  95. /*
  96. * If we're a SPI stage 2 bootloader, cut off the _spi_stage2
  97. * part of the name.
  98. */
  99. substr = strcasestr(board_name, "_spi_stage2");
  100. if (substr && (substr[strlen("_spi_stage2")] == '\0')) {
  101. printf(" Converting board name %s to ", board_name);
  102. *substr = '\0';
  103. printf("%s\n", board_name);
  104. }
  105. for (i = CVMX_BOARD_TYPE_NULL; i < CVMX_BOARD_TYPE_MAX; i++)
  106. if (!strcasecmp(cvmx_board_type_to_string(i), board_name))
  107. board_type = i;
  108. for (i = CVMX_BOARD_TYPE_CUST_DEFINED_MIN;
  109. i < CVMX_BOARD_TYPE_CUST_DEFINED_MAX; i++)
  110. if (!strncasecmp(cvmx_board_type_to_string(i), board_name,
  111. strlen(cvmx_board_type_to_string(i))))
  112. board_type = i;
  113. for (i = CVMX_BOARD_TYPE_CUST_PRIVATE_MIN;
  114. i < CVMX_BOARD_TYPE_CUST_PRIVATE_MAX; i++)
  115. if (!strncasecmp(cvmx_board_type_to_string(i), board_name,
  116. strlen(cvmx_board_type_to_string(i))))
  117. board_type = i;
  118. return board_type;
  119. }
  120. static void usage(void)
  121. {
  122. printf("Usage: update_octeon_header <filename> <board_name> [--failsafe] [--text_base=0xXXXXX]\n");
  123. }
  124. int main(int argc, char *argv[])
  125. {
  126. int fd;
  127. uint8_t buf[BUF_SIZE];
  128. uint32_t data_crc = 0;
  129. int len;
  130. int data_len = 0;
  131. struct bootloader_header header;
  132. char filename[NAME_LEN];
  133. int i;
  134. int option_index = 0; /* getopt_long stores the option index here. */
  135. char board_name[NAME_LEN] = { 0 };
  136. char tmp_board_name[NAME_LEN] = { 0 };
  137. int c;
  138. int board_type = 0;
  139. unsigned long long address = 0;
  140. ssize_t ret;
  141. const char *type_str = NULL;
  142. int hdr_size = sizeof(struct bootloader_header);
  143. /*
  144. * Compile time check, if the size of the bootloader_header structure
  145. * has changed.
  146. */
  147. compiletime_assert(sizeof(struct bootloader_header) == 192,
  148. "Octeon bootloader header size changed (!= 192)!");
  149. /* Bail out, if argument count is incorrect */
  150. if (argc < 3) {
  151. usage();
  152. return -1;
  153. }
  154. debug("header size is: %d bytes\n", hdr_size);
  155. /* Parse command line options using getopt_long */
  156. while (1) {
  157. c = getopt_long(argc, argv, "h", long_options, &option_index);
  158. /* Detect the end of the options. */
  159. if (c == -1)
  160. break;
  161. switch (c) {
  162. /* All long options handled in case 0 */
  163. case 0:
  164. /* If this option set a flag, do nothing else now. */
  165. if (long_options[option_index].flag != 0)
  166. break;
  167. debug("option(l) %s", long_options[option_index].name);
  168. if (!optarg) {
  169. usage();
  170. return -1;
  171. }
  172. debug(" with arg %s\n", optarg);
  173. if (!strcmp(long_options[option_index].name, "board")) {
  174. if (strlen(optarg) >= NAME_LEN) {
  175. printf("strncpy() issue detected!");
  176. exit(-1);
  177. }
  178. strncpy(board_name, optarg, NAME_LEN);
  179. printf("Using user supplied board name: %s\n",
  180. board_name);
  181. } else if (!strcmp(long_options[option_index].name,
  182. "text_base")) {
  183. address = strtoull(optarg, NULL, 0);
  184. printf("Address of image is: 0x%llx\n",
  185. (unsigned long long)address);
  186. if (!(address & 0xFFFFFFFFULL << 32)) {
  187. if (address & 1 << 31) {
  188. address |= 0xFFFFFFFFULL << 32;
  189. printf("Converting address to 64 bit compatibility space: 0x%llx\n",
  190. address);
  191. }
  192. }
  193. }
  194. break;
  195. case 'h':
  196. case '?':
  197. /* getopt_long already printed an error message. */
  198. usage();
  199. return -1;
  200. default:
  201. abort();
  202. }
  203. }
  204. if (optind < argc) {
  205. /*
  206. * We only support one argument - an optional bootloader
  207. * file name
  208. */
  209. if (argc - optind > 2) {
  210. fprintf(stderr, "non-option ARGV-elements: ");
  211. while (optind < argc)
  212. fprintf(stderr, "%s ", argv[optind++]);
  213. fprintf(stderr, "\n");
  214. usage();
  215. return -1;
  216. }
  217. }
  218. if (strlen(argv[optind]) >= NAME_LEN) {
  219. fprintf(stderr, "strncpy() issue detected!");
  220. exit(-1);
  221. }
  222. strncpy(filename, argv[optind], NAME_LEN);
  223. if (board_name[0] == '\0') {
  224. if (strlen(argv[optind + 1]) >= NAME_LEN) {
  225. fprintf(stderr, "strncpy() issue detected!");
  226. exit(-1);
  227. }
  228. strncpy(board_name, argv[optind + 1], NAME_LEN);
  229. }
  230. if (strlen(board_name) >= NAME_LEN) {
  231. fprintf(stderr, "strncpy() issue detected!");
  232. exit(-1);
  233. }
  234. strncpy(tmp_board_name, board_name, NAME_LEN);
  235. fd = open(filename, O_RDWR);
  236. if (fd < 0) {
  237. fprintf(stderr, "Unable to open file: %s\n", filename);
  238. exit(-1);
  239. }
  240. if (failsafe_flag)
  241. printf("Setting failsafe flag\n");
  242. if (strlen(board_name)) {
  243. int offset = 0;
  244. printf("Supplied board name of: %s\n", board_name);
  245. if (strstr(board_name, "failsafe")) {
  246. failsafe_flag = 1;
  247. printf("Setting failsafe flag based on board name\n");
  248. }
  249. /* Skip leading octeon_ if present. */
  250. if (!strncmp(board_name, "octeon_", 7))
  251. offset = 7;
  252. /*
  253. * Check to see if 'failsafe' is in the name. If so, set the
  254. * failsafe flag. Also, ignore extra trailing characters on
  255. * passed parameter when comparing against board names.
  256. * We actually use the configuration name from u-boot, so it
  257. * may have some other variant names. Variants other than
  258. * failsafe _must_ be passed to this program explicitly
  259. */
  260. board_type = lookup_board_type(board_name + offset);
  261. if (!board_type) {
  262. /* Retry with 'cust_' prefix to catch boards that are
  263. * in the customer section (such as nb5)
  264. */
  265. sprintf(tmp_board_name, "cust_%s", board_name + offset);
  266. board_type = lookup_board_type(tmp_board_name);
  267. }
  268. /* reset to original value */
  269. strncpy(tmp_board_name, board_name, NAME_LEN);
  270. if (!board_type) {
  271. /*
  272. * Retry with 'cust_private_' prefix to catch boards
  273. * that are in the customer private section
  274. */
  275. sprintf(tmp_board_name, "cust_private_%s",
  276. board_name + offset);
  277. board_type = lookup_board_type(tmp_board_name);
  278. }
  279. if (!board_type) {
  280. fprintf(stderr,
  281. "ERROR: unable to determine board type\n");
  282. exit(-1);
  283. }
  284. printf("Board type is: %d: %s\n", board_type,
  285. cvmx_board_type_to_string(board_type));
  286. } else {
  287. fprintf(stderr, "Board name must be specified!\n");
  288. exit(-1);
  289. }
  290. /*
  291. * Check to see if there is either an existing header, or that there
  292. * are zero valued bytes where we want to put the header
  293. */
  294. len = read(fd, buf, BUF_SIZE);
  295. if (len > 0) {
  296. /*
  297. * Copy the header, as the first word (jump instruction, needs
  298. * to remain the same.
  299. */
  300. memcpy(&header, buf, hdr_size);
  301. /*
  302. * Check to see if we have zero bytes (excluding first 4, which
  303. * are the jump instruction)
  304. */
  305. for (i = 1; i < hdr_size / 4; i++) {
  306. if (((uint32_t *)buf)[i]) {
  307. fprintf(stderr,
  308. "ERROR: non-zero word found %x in location %d required for header, aborting\n",
  309. ((uint32_t *)buf)[i], i);
  310. exit(-1);
  311. }
  312. }
  313. printf("Zero bytes found in header location, adding header.\n");
  314. } else {
  315. fprintf(stderr, "Unable to read from file %s\n", filename);
  316. exit(-1);
  317. }
  318. /* Read data bytes and generate CRC */
  319. lseek(fd, hdr_size, SEEK_SET);
  320. while ((len = read(fd, buf, BUF_SIZE)) > 0) {
  321. data_crc = crc32(data_crc, buf, len);
  322. data_len += len;
  323. }
  324. printf("CRC of data: 0x%x, length: %d\n", data_crc, data_len);
  325. /* Now create the new header */
  326. header.magic = htonl(BOOTLOADER_HEADER_MAGIC);
  327. header.maj_rev = htons(BOOTLOADER_HEADER_CURRENT_MAJOR_REV);
  328. header.min_rev = htons(BOOTLOADER_HEADER_CURRENT_MINOR_REV);
  329. header.dlen = htonl(data_len);
  330. header.dcrc = htonl(data_crc);
  331. header.board_type = htons(board_type);
  332. header.address = address;
  333. if (failsafe_flag)
  334. header.flags |= htonl(BL_HEADER_FLAG_FAILSAFE);
  335. printf("Stage 2 flag is %sset\n", stage2_flag ? "" : "not ");
  336. printf("Stage 1 flag is %sset\n", stage_1_flag ? "" : "not ");
  337. if (pciboot_flag)
  338. header.image_type = htons(BL_HEADER_IMAGE_PCIBOOT);
  339. else if (stage2_flag)
  340. header.image_type = htons(BL_HEADER_IMAGE_STAGE2);
  341. else if (stage_1_flag)
  342. header.image_type = htons(BL_HEADER_IMAGE_STAGE1);
  343. else if (env_flag)
  344. header.image_type = htons(BL_HEADER_IMAGE_UBOOT_ENV);
  345. else if (stage_1_5_flag || stage_1_flag)
  346. header.image_type = htons(BL_HEADER_IMAGE_PRE_UBOOT);
  347. else
  348. header.image_type = htons(BL_HEADER_IMAGE_NOR);
  349. switch (ntohs(header.image_type)) {
  350. case BL_HEADER_IMAGE_UNKNOWN:
  351. type_str = "Unknown";
  352. break;
  353. case BL_HEADER_IMAGE_STAGE1:
  354. type_str = "Stage 1";
  355. break;
  356. case BL_HEADER_IMAGE_STAGE2:
  357. type_str = "Stage 2";
  358. break;
  359. case BL_HEADER_IMAGE_PRE_UBOOT:
  360. type_str = "Pre-U-Boot";
  361. break;
  362. case BL_HEADER_IMAGE_STAGE3:
  363. type_str = "Stage 3";
  364. break;
  365. case BL_HEADER_IMAGE_NOR:
  366. type_str = "NOR";
  367. break;
  368. case BL_HEADER_IMAGE_PCIBOOT:
  369. type_str = "PCI Boot";
  370. break;
  371. case BL_HEADER_IMAGE_UBOOT_ENV:
  372. type_str = "U-Boot Environment";
  373. break;
  374. default:
  375. if (ntohs(header.image_type) >= BL_HEADER_IMAGE_CUST_RESERVED_MIN &&
  376. ntohs(header.image_type) <= BL_HEADER_IMAGE_CUST_RESERVED_MAX)
  377. type_str = "Customer Reserved";
  378. else
  379. type_str = "Unsupported";
  380. }
  381. printf("Header image type: %s\n", type_str);
  382. header.hlen = htons(hdr_size);
  383. /* Now compute header CRC over all of the header excluding the CRC */
  384. header.hcrc = crc32(0, (void *)&header, 12);
  385. header.hcrc = htonl(crc32(header.hcrc, ((void *)&(header)) + 16,
  386. hdr_size - 16));
  387. /* Seek to beginning of file */
  388. lseek(fd, 0, SEEK_SET);
  389. /* Write header to file */
  390. ret = write(fd, &header, hdr_size);
  391. if (ret < 0)
  392. perror("write");
  393. close(fd);
  394. printf("Header CRC: 0x%x\n", ntohl(header.hcrc));
  395. return 0;
  396. }