2 * Copyright (C) 2016 Piotr Dymacz <piotr@dymacz.pl>
3 * Copyright (C) 2000-2006 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
5 * SPDX-License-Identifier: GPL-2.0
14 #include <tplink_image.h>
16 #include <LzmaWrapper.h>
17 #include <environment.h>
18 #include <asm/byteorder.h>
21 #ifdef CFG_HUSH_PARSER
25 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
29 DECLARE_GLOBAL_DATA_PTR;
31 extern void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
32 extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
33 extern void eth_halt(void);
35 /* U-Boot type image header */
36 image_header_t header;
38 /* Default load address */
39 u32 load_addr = CFG_LOAD_ADDR;
41 #define TPL_ALIGN_SIZE 21
42 #define UBOOT_ALIGN_SIZE 14
45 * Clears console variable from command line
47 #ifdef CONFIG_SILENT_CONSOLE
48 static void fixup_silent_linux(void)
51 char *cmdline, *end, *start;
53 /* Only fix cmdline when requested */
54 if (!(gd->flags & GD_FLG_SILENT)) {
58 cmdline = getenv("bootargs");
61 if ((start = strstr(cmdline, "console=")) != NULL) {
62 end = strchr(start, ' ');
63 strncpy(buf, cmdline, (start - cmdline + 8));
66 strcpy(buf + (start - cmdline + 8), end);
68 buf[start - cmdline + 8] = '\0';
72 strcat(buf, " console=");
75 strcpy(buf, "console=");
78 setenv("bootargs", buf);
80 #endif /* CONFIG_SILENT_CONSOLE */
83 * Prints information about TP-Link
84 * firmware format from header
86 static void print_tpl_ih_v1(tplink_image_header_t *hdr)
90 /* Image/vendor name */
91 printf(" %-*s ", TPL_ALIGN_SIZE, "Vendor/image name:");
93 sizeof(hdr->ih_vendor), hdr->ih_vendor,
94 sizeof(hdr->ih_info), hdr->ih_info);
96 /* Version (for vendor firmware only) */
97 if (hdr->ih_fw_ver_hi > 0) {
98 printf(" %-*s ", TPL_ALIGN_SIZE, "Firmware version:");
100 ntohl(hdr->ih_fw_ver_hi),
101 ntohl(hdr->ih_fw_ver_mid),
102 ntohl(hdr->ih_fw_ver_lo));
106 printf(" %-*s ", TPL_ALIGN_SIZE, "Hardware ID:");
107 printf("0x%X\n", ntohl(hdr->ih_hw_id));
109 /* Sizes of firmware parts */
110 printf(" %-*s ", TPL_ALIGN_SIZE, "Whole image size:");
111 print_size(ntohl(hdr->ih_fw_len), " ");
112 printf("(%d bytes)\n", ntohl(hdr->ih_fw_len));
114 printf(" %-*s ", TPL_ALIGN_SIZE, "Kernel size:");
115 print_size(ntohl(hdr->ih_kernel_len), " ");
116 printf("(%d bytes)\n", ntohl(hdr->ih_kernel_len));
118 printf(" %-*s ", TPL_ALIGN_SIZE, "Rootfs size:");
119 print_size(ntohl(hdr->ih_rootfs_len), " ");
120 printf("(%d bytes)\n", ntohl(hdr->ih_rootfs_len));
122 printf(" %-*s ", TPL_ALIGN_SIZE, "Kernel load address:");
123 printf("0x%08X\n", ntohl(hdr->ih_kernel_load));
125 printf(" %-*s ", TPL_ALIGN_SIZE, "Kernel entry point:");
126 printf("0x%08X\n", ntohl(hdr->ih_kernel_ep));
128 /* TODO: MD5 sum verify */
134 * Returns image type in text
136 static char *ih_img_type(uint8_t img)
144 case IH_TYPE_INVALID:
146 case IH_TYPE_STANDALONE:
147 return "Standalone program";
148 case IH_TYPE_RAMDISK:
150 case IH_TYPE_FIRMWARE:
161 * Returns architecture type in text
163 static char *ih_arch_type(uint8_t arch)
170 return "Invalid CPU";
180 return "MIPS 64-bit";
190 return "SPARC 64-bit";
193 case IH_CPU_MICROBLAZE:
206 * Returns compression type in text
208 static char *ih_comp_type(uint8_t comp)
227 * Returns operating system type in text
229 static char *ih_os_type(uint8_t os)
254 * Prints information about standard
255 * U-Boot image format from header
257 static void print_uboot_ih(image_header_t *hdr)
262 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
264 time_t timestamp = (time_t)ntohl(hdr->ih_time);
269 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Image name:");
270 printf("%.*s\n", sizeof(hdr->ih_name), hdr->ih_name);
272 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
273 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Build date:");
274 to_tm(timestamp, &tm);
275 printf("%4d-%02d-%02d %02d:%02d:%02d UTC\n",
276 tm.tm_year, tm.tm_mon, tm.tm_mday,
277 tm.tm_hour, tm.tm_min, tm.tm_sec);
280 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Architecture:");
281 printf("%s\n", ih_arch_type(hdr->ih_arch));
283 printf(" %-*s ", UBOOT_ALIGN_SIZE, "OS/image type:");
284 printf("%s %s\n", ih_os_type(hdr->ih_os), ih_img_type(hdr->ih_type));
286 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Compression:");
287 printf("%s\n", ih_comp_type(hdr->ih_comp));
289 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Data size:");
290 print_size(ntohl(hdr->ih_size), " ");
291 printf("(%d bytes)\n", ntohl(hdr->ih_size));
293 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Load address:");
294 printf("0x%08X\n", ntohl(hdr->ih_load));
296 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Entry point:");
297 printf("0x%08X\n", ntohl(hdr->ih_ep));
299 if (hdr->ih_type == IH_TYPE_MULTI) {
300 len_ptr = (u32 *)((u32)hdr + sizeof(image_header_t));
302 printf("\n %-*s\n", UBOOT_ALIGN_SIZE, "Multi-File:");
304 for (i = 0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
306 print_size(len, " ");
307 printf("(%d bytes)\n", len);
315 * Verifies U-Boot image data checksum
317 static int ih_data_crc(u32 addr, image_header_t *hdr, int tpl_type, int verify)
321 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Data CRC...");
323 if (tpl_type == 0 && verify == 1) {
324 if (tinf_crc32((u8 *)addr, ntohl(hdr->ih_size))
325 != ntohl(hdr->ih_dcrc)) {
339 * Verifies U-Boot image header checksum
341 static int ih_header_crc(image_header_t *hdr, int tpl_type)
346 printf(" %-*s ", UBOOT_ALIGN_SIZE, "Header CRC...");
349 crc = ntohl(hdr->ih_hcrc);
352 if (tinf_crc32((u8 *)hdr, sizeof(image_header_t)) != crc) {
368 * Converts TP-Link header to stanard
369 * U-Boot image format header
371 static void tpl_to_uboot_header(image_header_t *hdr,
372 tplink_image_header_t *tpl_hdr)
374 memset(hdr, 0, sizeof(image_header_t));
376 /* Set only needed values */
380 hdr->ih_ep = htonl(tpl_hdr->ih_kernel_ep);
381 hdr->ih_size = htonl(tpl_hdr->ih_kernel_len);
382 hdr->ih_load = htonl(tpl_hdr->ih_kernel_load);
384 hdr->ih_os = IH_OS_LINUX;
385 hdr->ih_arch = IH_CPU_MIPS;
386 hdr->ih_type = IH_TYPE_KERNEL;
387 hdr->ih_comp = IH_COMP_LZMA;
390 int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
395 int i, tpl_type, verify;
396 u32 unc_len = CFG_BOOTM_LEN;
397 image_header_t *hdr = &header;
398 tplink_image_header_t *tpl_hdr;
401 * By default don't verify data CRC checksum,
402 * but allow to enable it, using environment
404 s = getenv("verify_data");
405 verify = (s && (*s == 'y')) ? 1 : 0;
410 addr = simple_strtoul(argv[1], NULL, 16);
413 printf("Booting image from 0x%08lX...\n", addr);
415 /* Check what header type we have */
416 memmove(&data, (char *)addr, sizeof(u32));
419 switch (ntohl(data)) {
420 case TPL_IH_VERSION_V1:
423 tpl_hdr = (tplink_image_header_t *)addr;
424 print_tpl_ih_v1(tpl_hdr);
426 /* Convert to general format */
427 tpl_to_uboot_header(hdr, tpl_hdr);
430 print_uboot_ih((image_header_t *)addr);
431 memmove(&header, (char *)addr, sizeof(image_header_t));
433 case TPL_IH_VERSION_V2:
434 case TPL_IH_VERSION_V3:
436 puts("## Error: unsupported image header\n");
440 /* Always verify header CRC */
441 if (ih_header_crc(hdr, tpl_type) != 0) {
442 puts("## Error: header checksum mismatch!\n");
446 /* And data if enabled */
448 data = addr + sizeof(tplink_image_header_t);
450 data = addr + sizeof(image_header_t);
453 if (ih_data_crc(data, hdr, tpl_type, verify) != 0) {
454 puts("## Error: data checksum mismatch!\n");
460 len = ntohl(hdr->ih_size);
461 len_ptr = (u32 *)data;
463 /* We support only MIPS */
464 if (hdr->ih_arch != IH_CPU_MIPS) {
465 puts("## Error: unsupported architecture!\n");
470 switch (hdr->ih_type) {
474 /* OS kernel is always in first image */
475 len = ntohl(len_ptr[0]);
478 /* Move over list to first image */
479 for (i = 1; len_ptr[i]; ++i)
484 puts("## Error: unsupported image type!\n");
489 * We have reached the point of no return: we are going to
490 * overwrite all exception vector code, so we cannot easily
491 * recover from any failures any more...
494 #ifdef CONFIG_NETCONSOLE
496 * Stop the ethernet stack if NetConsole could have
499 puts("Stopping network... ");
504 /* TODO: should we flush caches for kernel? */
506 * Flush everything, restore caches for linux
508 //mips_cache_flush();
509 //mips_icache_flush_ix();
511 /* XXX - this causes problems when booting from flash */
512 /* dcache_disable(); */
514 /* Compression type... */
515 switch (hdr->ih_comp) {
517 printf("Uncompressing %s... ", ih_img_type(hdr->ih_type));
519 /* Try to extract LZMA data... */
520 i = lzma_inflate((u8 *)data, len,
521 (u8 *)ntohl(hdr->ih_load), (int *)&unc_len);
523 /* TODO: more verbose LZMA errors */
524 if (i != LZMA_RESULT_OK) {
526 printf("## Error: LZMA error '%d'!\n", i);
533 printf("## Error: unsupported compression type '%s'!\n",
534 ih_comp_type(hdr->ih_comp));
539 #ifdef CONFIG_SILENT_CONSOLE
540 fixup_silent_linux();
543 do_bootm_linux(cmdtp, flag, argc, argv);
548 U_BOOT_CMD(bootm, 2, 1, do_bootm,
549 "boot application image from memory\n", "[addr]\n"
550 "\t- boot application image stored in memory at address 'addr'\n");
552 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
553 int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
555 #ifndef CFG_HUSH_PARSER
556 if (run_command(getenv("bootcmd"), flag) < 0)
559 if (parse_string_outer(getenv("bootcmd"),
560 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
567 U_BOOT_CMD(boot, 1, 1, do_bootd, "boot default, run 'bootcmd'\n", NULL);
568 #endif /* CONFIG_COMMANDS & CFG_CMD_BOOTD */
570 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
571 int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
575 image_header_t *hdr = &header;
576 tplink_image_header_t *tpl_hdr;
581 addr = simple_strtoul(argv[1], NULL, 16);
583 print_cmd_help(cmdtp);
587 printf("\nChecking image at 0x%08lX...\n", addr);
589 /* Check what header type we have */
590 memmove(&data, (char *)addr, sizeof(u32));
592 switch (ntohl(data)) {
593 case TPL_IH_VERSION_V1:
596 tpl_hdr = (tplink_image_header_t *)addr;
597 print_tpl_ih_v1(tpl_hdr);
600 print_uboot_ih((image_header_t *)addr);
601 memmove(&header, (char *)addr, sizeof(image_header_t));
603 case TPL_IH_VERSION_V2:
604 case TPL_IH_VERSION_V3:
606 puts("## Error: unsupported image header\n");
610 /* Always verify header CRC */
611 if (ih_header_crc(hdr, tpl_type) != 0) {
612 puts("## Error: header checksum mismatch!\n");
616 /* And data.. here always */
618 data = addr + sizeof(tplink_image_header_t);
620 data = addr + sizeof(image_header_t);
623 if (ih_data_crc(data, hdr, tpl_type, 1) != 0) {
624 puts("## Error: data checksum mismatch!\n");
633 U_BOOT_CMD(iminfo, 2, 1, do_iminfo,
634 "print firmware header\n", "address\n"
635 "\t- print header information for image at 'address'\n");
636 #endif /* CFG_CMD_IMI */