Cleanups in bootm command and related code
authorPiotr Dymacz <pepe2k@gmail.com>
Sun, 14 Aug 2016 08:33:03 +0000 (10:33 +0200)
committerPiotr Dymacz <pepe2k@gmail.com>
Sun, 14 Aug 2016 08:33:03 +0000 (10:33 +0200)
Instead of selecting supported header type (standard U-Boot image
or custom TP-Link) at compile time, from now both headers are
supported. This allows to use both image types on all devices,
which sometimes might be useful.

Other changes:

- clean up code style, use tab size = 8
- restore support for Multi-File image, used in some ZBT routers
- add new TP-Link image header definition, get rid of old one
- restore CRC checksum tests (for image header and data)
- make image header information look better, include more data
- remove bootd command, as it was only alias for boot command

u-boot/common/cmd_bootm.c
u-boot/include/common.h
u-boot/include/tpLinuxTag.h [deleted file]
u-boot/include/tplink_image.h [new file with mode: 0644]

index b5072b746cadc6b68ff4fab4299c1ffb869f42d4..627a09d892af0d593aeb016812511109a4b068f5 100644 (file)
@@ -1,24 +1,8 @@
 /*
- * (C) Copyright 2000-2006
- * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
+ * Copyright (C) 2016 Piotr Dymacz <piotr@dymacz.pl>
+ * Copyright (C) 2000-2006 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
  *
- * See file CREDITS for list of people who contributed to this
- * project.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
- * MA 02111-1307 USA
+ * SPDX-License-Identifier: GPL-2.0
  */
 
 /*
 #include <common.h>
 #include <command.h>
 #include <image.h>
+#include <tplink_image.h>
 #include <malloc.h>
 #include <LzmaWrapper.h>
 #include <environment.h>
 #include <asm/byteorder.h>
 #include <tinf.h>
 
-DECLARE_GLOBAL_DATA_PTR;
-
 #ifdef CFG_HUSH_PARSER
 #include <hush.h>
 #endif
 
-/* cmd_boot.c */
-extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
-
-/* net.c */
-extern void eth_halt(void);
-
 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
 #include <rtc.h>
 #endif
 
-/*
- *  Continue booting an OS image; caller already has:
- *  - copied image header to global variable `header'
- *  - checked header magic number, checksums (both header & image),
- *  - verified image architecture (PPC) and type (KERNEL or MULTI),
- *  - loaded (first part of) image to header load address,
- *  - disabled interrupts.
- */
+DECLARE_GLOBAL_DATA_PTR;
+
 extern void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern int  do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
+extern void eth_halt(void);
 
-#ifdef CONFIG_SILENT_CONSOLE
-static void fixup_silent_linux(void);
-#endif
+/* U-Boot type image header */
+image_header_t header;
 
-#if (CONFIG_COMMANDS & CFG_CMD_IMI)
-static int image_info(unsigned long addr);
-#endif
+/* Default load address */
+u32 load_addr = CFG_LOAD_ADDR;
 
-image_header_t header;
-ulong load_addr = CFG_LOAD_ADDR; /* default load address */
+#define TPL_ALIGN_SIZE         21
+#define UBOOT_ALIGN_SIZE       14
 
-#ifdef CONFIG_TPLINK_IMAGE_HEADER
-void fake_image_header(image_header_t *hdr, tplink_image_header_t *tpl_hdr){
-       memset(hdr, 0, sizeof(image_header_t));
+/*
+ * Clears console variable from command line
+ */
+#ifdef CONFIG_SILENT_CONSOLE
+static void fixup_silent_linux(void)
+{
+       char buf[256];
+       char *cmdline, *end, *start;
 
-       /* Build new header */
-       hdr->ih_magic   = htonl(IH_MAGIC);
-       hdr->ih_hcrc    = 0;
-       hdr->ih_time    = 0;
-       hdr->ih_size    = htonl(tpl_hdr->kernelLen);
-       hdr->ih_load    = htonl(tpl_hdr->kernelTextAddr);
-       hdr->ih_ep              = htonl(tpl_hdr->kernelEntryPoint);
-       hdr->ih_dcrc    = 0;
-       hdr->ih_os              = IH_OS_LINUX;
-       hdr->ih_arch    = IH_CPU_MIPS;
-       hdr->ih_type    = IH_TYPE_KERNEL;
-       hdr->ih_comp    = IH_COMP_LZMA;
-
-       strncpy((char *)hdr->ih_name, (char *)tpl_hdr->signiture_1, IH_NMLEN);
-}
-#endif /* CONFIG_TPLINK_IMAGE_HEADER */
+       /* Only fix cmdline when requested */
+       if (!(gd->flags & GD_FLG_SILENT)) {
+               return;
+       }
 
-int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
-       ulong addr, data, len;
-       uint unc_len = CFG_BOOTM_LEN;
-       int i;
-       image_header_t *hdr = &header;
-#ifdef CONFIG_TPLINK_IMAGE_HEADER
-       tplink_image_header_t *fileTag;
-#endif
+       cmdline = getenv("bootargs");
 
-       if(argc < 2){
-               addr = load_addr;
+       if (cmdline) {
+               if ((start = strstr(cmdline, "console=")) != NULL) {
+                       end = strchr(start, ' ');
+                       strncpy(buf, cmdline, (start - cmdline + 8));
+
+                       if (end) {
+                               strcpy(buf + (start - cmdline + 8), end);
+                       } else {
+                               buf[start - cmdline + 8] = '\0';
+                       }
+               } else {
+                       strcpy(buf, cmdline);
+                       strcat(buf, " console=");
+               }
        } else {
-               addr = simple_strtoul(argv[1], NULL, 16);
+               strcpy(buf, "console=");
        }
 
-       printf("Booting image at: 0x%08lX\n", addr);
+       setenv("bootargs", buf);
+}
+#endif /* CONFIG_SILENT_CONSOLE */
 
-#ifndef CONFIG_TPLINK_IMAGE_HEADER
-       memmove(&header, (char *)addr, sizeof(image_header_t));
-       print_image_hdr(hdr);
+/*
+ * Prints information about TP-Link
+ * firmware format from header
+ */
+static void print_tpl_ih_v1(tplink_image_header_t *hdr)
+{
+       puts("\n");
 
-       data = addr + sizeof(image_header_t);
-#else
-       fileTag = (tplink_image_header_t *)addr;
-       print_image_hdr(fileTag);
+       /* Image/vendor name */
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Vendor/image name:");
+       printf("%.*s %.*s\n",
+               sizeof(hdr->ih_vendor), hdr->ih_vendor,
+               sizeof(hdr->ih_info), hdr->ih_info);
+
+       /* Version (for vendor firmware only) */
+       if (hdr->ih_fw_ver_hi > 0) {
+               printf("   %-*s ", TPL_ALIGN_SIZE, "Firmware version:");
+               printf("%d.%d.%d\n",
+                       ntohl(hdr->ih_fw_ver_hi),
+                       ntohl(hdr->ih_fw_ver_mid),
+                       ntohl(hdr->ih_fw_ver_lo));
+       }
 
-       fake_image_header(hdr, fileTag);
+       /* Hardware id */
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Hardware ID:");
+       printf("0x%X\n", ntohl(hdr->ih_hw_id));
 
-       data = addr + TAG_LEN;
-#endif /* !CONFIG_TPLINK_IMAGE_HEADER */
+       /* Sizes of firmware parts */
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Whole image size:");
+       print_size(ntohl(hdr->ih_fw_len), " ");
+       printf("(%d bytes)\n", ntohl(hdr->ih_fw_len));
 
-       len = ntohl(hdr->ih_size);
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Kernel size:");
+       print_size(ntohl(hdr->ih_kernel_len), " ");
+       printf("(%d bytes)\n", ntohl(hdr->ih_kernel_len));
 
-       /*
-        * We have reached the point of no return: we are going to
-        * overwrite all exception vector code, so we cannot easily
-        * recover from any failures any more...
-        */
-#ifdef CONFIG_NETCONSOLE
-       /*
-       * Stop the ethernet stack if NetConsole could have
-       * left it up
-       */
-       eth_halt();
-#endif
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Rootfs size:");
+       print_size(ntohl(hdr->ih_rootfs_len), " ");
+       printf("(%d bytes)\n", ntohl(hdr->ih_rootfs_len));
 
-       /* TODO: should we flush caches for kernel? */
-       /*
-        * Flush everything, restore caches for linux
-        */
-       //mips_cache_flush();
-       //mips_icache_flush_ix();
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Kernel load address:");
+       printf("0x%08X\n", ntohl(hdr->ih_kernel_load));
 
-       /* XXX - this causes problems when booting from flash */
-       /* dcache_disable(); */
+       printf("   %-*s ", TPL_ALIGN_SIZE, "Kernel entry point:");
+       printf("0x%08X\n", ntohl(hdr->ih_kernel_ep));
 
-       /*      case IH_COMP_LZMA:*/
-       puts("Uncompressing kernel image... ");
+       /* TODO: MD5 sum verify */
 
-       i = lzma_inflate((unsigned char *)data, len, (unsigned char*)ntohl(hdr->ih_load), (int *)&unc_len);
+       puts("\n");
+}
 
-       if(i != LZMA_RESULT_OK){
-               printf("## Error: LZMA error num: %d\n", i);
-               return(-1);
+/*
+ * Returns image type in text
+ */
+static char *ih_img_type(uint8_t img)
+{
+       switch (img) {
+       case IH_TYPE_KERNEL:
+               return "Kernel";
+       case IH_TYPE_MULTI:
+               return "Multi-File";
+/*
+       case IH_TYPE_INVALID:
+               return "Invalid";
+       case IH_TYPE_STANDALONE:
+               return "Standalone program";
+       case IH_TYPE_RAMDISK:
+               return "RAMDisk";
+       case IH_TYPE_FIRMWARE:
+               return "Firmware";
+       case IH_TYPE_SCRIPT:
+               return "Script";
+*/
+       default:
+               return "unknown";
        }
+}
 
-       puts("OK!\n");
+/*
+ * Returns architecture type in text
+ */
+static char *ih_arch_type(uint8_t arch)
+{
+       switch (arch) {
+       case IH_CPU_MIPS:
+               return "MIPS";
+/*
+       case IH_CPU_INVALID:
+               return "Invalid CPU";
+       case IH_CPU_ALPHA:
+               return "Alpha";
+       case IH_CPU_ARM:
+               return "ARM";
+       case IH_CPU_I386:
+               return "Intel x86";
+       case IH_CPU_IA64:
+               return "IA64";
+       case IH_CPU_MIPS64:
+               return "MIPS 64-bit";
+       case IH_CPU_PPC:
+               return "PowerPC";
+       case IH_CPU_S390:
+               return "IBM S390";
+       case IH_CPU_SH:
+               return "SuperH";
+       case IH_CPU_SPARC:
+               return "SPARC";
+       case IH_CPU_SPARC64:
+               return "SPARC 64-bit";
+       case IH_CPU_M68K:
+               return "M68K";
+       case IH_CPU_MICROBLAZE:
+               return "Microblaze";
+       case IH_CPU_NIOS:
+               return "Nios";
+       case IH_CPU_NIOS2:
+               return "Nios-II";
+*/
+       default:
+               return "unknown";
+       }
+}
 
-#ifdef CONFIG_SILENT_CONSOLE
-       fixup_silent_linux();
+/*
+ * Returns compression type in text
+ */
+static char *ih_comp_type(uint8_t comp)
+{
+       switch (comp) {
+       case IH_COMP_LZMA:
+               return "LZMA";
+/*
+       case IH_COMP_NONE:
+               return "none";
+       case IH_COMP_GZIP:
+               return "GZIP";
+       case IH_COMP_BZIP2:
+               return "BZIP2";
+*/
+       default:
+               return "unknown";
+       }
+}
+
+/*
+ * Returns operating system type in text
+ */
+static char *ih_os_type(uint8_t os)
+{
+       switch (os) {
+       case IH_OS_LINUX:
+               return "Linux";
+/*
+       case IH_OS_INVALID:
+               return "Invalid OS";
+       case IH_OS_NETBSD:
+               return "NetBSD";
+       case IH_OS_VXWORKS:
+               return "VxWorks";
+       case IH_OS_QNX:
+               return "QNX";
+       case IH_OS_U_BOOT:
+               return "U-Boot";
+       case IH_OS_RTEMS:
+               return "RTEMS";
+*/
+       default:
+               return "unknown";
+       }
+}
+
+/*
+ * Prints information about standard
+ * U-Boot image format from header
+ */
+static void print_uboot_ih(image_header_t *hdr)
+{
+       int i;
+       u32 len;
+       u32 *len_ptr;
+#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
+       struct rtc_time tm;
+       time_t timestamp = (time_t)ntohl(hdr->ih_time);
 #endif
 
-       do_bootm_linux(cmdtp, flag, argc, argv);
+       puts("\n");
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Image name:");
+       printf("%.*s\n", sizeof(hdr->ih_name), hdr->ih_name);
 
-#ifdef DEBUG
-       puts("\n## Error: control returned to monitor - resetting...\n");
-       do_reset(cmdtp, flag, argc, argv);
+#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Build date:");
+       to_tm(timestamp, &tm);
+       printf("%4d-%02d-%02d %02d:%02d:%02d UTC\n",
+               tm.tm_year, tm.tm_mon, tm.tm_mday,
+               tm.tm_hour, tm.tm_min, tm.tm_sec);
 #endif
 
-       return(1);
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Architecture:");
+       printf("%s\n", ih_arch_type(hdr->ih_arch));
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "OS/image type:");
+       printf("%s %s\n", ih_os_type(hdr->ih_os), ih_img_type(hdr->ih_type));
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Compression:");
+       printf("%s\n", ih_comp_type(hdr->ih_comp));
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Data size:");
+       print_size(ntohl(hdr->ih_size), " ");
+       printf("(%d bytes)\n", ntohl(hdr->ih_size));
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Load address:");
+       printf("0x%08X\n", ntohl(hdr->ih_load));
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Entry point:");
+       printf("0x%08X\n", ntohl(hdr->ih_ep));
+
+       if (hdr->ih_type == IH_TYPE_MULTI) {
+               len_ptr = (u32 *)((u32)hdr + sizeof(image_header_t));
+
+               printf("\n   %-*s\n", UBOOT_ALIGN_SIZE, "Multi-File:");
+
+               for (i = 0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
+                       puts("   > ");
+                       print_size(len, " ");
+                       printf("(%d bytes)\n", len);
+               }
+       }
+
+       puts("\n");
 }
 
-U_BOOT_CMD(bootm, 2, 1, do_bootm, "boot application image from memory\n", "[addr]\n"
-"\t- boot application image stored in memory at address 'addr'\n");
+/*
+ * Verifies U-Boot image data checksum
+ */
+static int ih_data_crc(u32 addr, image_header_t *hdr, int tpl_type, int verify)
+{
+       int ret = 0;
 
-#ifdef CONFIG_SILENT_CONSOLE
-static void fixup_silent_linux(){
-       char buf[256], *start, *end;
-       char *cmdline = getenv("bootargs");
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Data CRC...");
 
-       /* Only fix cmdline when requested */
-       if(!(gd->flags & GD_FLG_SILENT)){
-               return;
+       if (tpl_type == 0 && verify == 1) {
+               if (tinf_crc32((u8 *)addr, ntohl(hdr->ih_size))
+                   != ntohl(hdr->ih_dcrc)) {
+                       puts("ERROR\n\n");
+                       ret = 1;
+               } else {
+                       puts("OK!\n");
+               }
+       } else {
+               puts("skipped\n");
        }
 
-#ifdef DEBUG
-       printf("before silent fix-up: %s\n", cmdline);
-#endif
+       return ret;
+}
 
-       if(cmdline){
-               if((start = strstr(cmdline, "console=")) != NULL){
-                       end = strchr(start, ' ');
-                       strncpy(buf, cmdline, (start - cmdline + 8));
-                       if(end){
-                               strcpy(buf + (start - cmdline + 8), end);
-                       } else {
-                               buf[start - cmdline + 8] = '\0';
-                       }
+/*
+ * Verifies U-Boot image header checksum
+ */
+static int ih_header_crc(image_header_t *hdr, int tpl_type)
+{
+       u32 crc;
+       int ret = 0;
+
+       printf("   %-*s ", UBOOT_ALIGN_SIZE, "Header CRC...");
+
+       if (tpl_type == 0) {
+               crc = ntohl(hdr->ih_hcrc);
+               hdr->ih_hcrc = 0;
+
+               if (tinf_crc32((u8 *)hdr, sizeof(image_header_t)) != crc) {
+                       puts("ERROR\n\n");
+                       ret = 1;
                } else {
-                       strcpy(buf, cmdline);
-                       strcat(buf, " console=");
+                       puts("OK!\n");
                }
+
+               hdr->ih_hcrc = crc;
        } else {
-               strcpy(buf, "console=");
+               puts("skipped\n");
        }
 
-       setenv("bootargs", buf);
-       debug("after silent fix-up: %s\n", buf);
+       return ret;
 }
-#endif /* CONFIG_SILENT_CONSOLE */
 
-#ifndef CONFIG_TPLINK_IMAGE_HEADER
-static void print_type(image_header_t *hdr){
-       char *os, *arch, *type, *comp;
-
-       switch(hdr->ih_os){
-               case IH_OS_INVALID:
-                       os = "Invalid OS";
-                       break;
-               case IH_OS_NETBSD:
-                       os = "NetBSD";
-                       break;
-               case IH_OS_LINUX:
-                       os = "Linux";
-                       break;
-               case IH_OS_VXWORKS:
-                       os = "VxWorks";
-                       break;
-               case IH_OS_QNX:
-                       os = "QNX";
-                       break;
-               case IH_OS_U_BOOT:
-                       os = "U-Boot";
-                       break;
-               case IH_OS_RTEMS:
-                       os = "RTEMS";
-                       break;
-               default:
-                       os = "Unknown OS";
-                       break;
+/*
+ * Converts TP-Link header to stanard
+ * U-Boot image format header
+ */
+static void tpl_to_uboot_header(image_header_t *hdr,
+                               tplink_image_header_t *tpl_hdr)
+{
+       memset(hdr, 0, sizeof(image_header_t));
+
+       /* Set only needed values */
+       hdr->ih_hcrc = 0;
+       hdr->ih_dcrc = 0;
+
+       hdr->ih_ep   = htonl(tpl_hdr->ih_kernel_ep);
+       hdr->ih_size = htonl(tpl_hdr->ih_kernel_len);
+       hdr->ih_load = htonl(tpl_hdr->ih_kernel_load);
+
+       hdr->ih_os   = IH_OS_LINUX;
+       hdr->ih_arch = IH_CPU_MIPS;
+       hdr->ih_type = IH_TYPE_KERNEL;
+       hdr->ih_comp = IH_COMP_LZMA;
+}
+
+int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+       char *s;
+       u32 *len_ptr;
+       u32 addr, data, len;
+       int i, tpl_type, verify;
+       u32 unc_len = CFG_BOOTM_LEN;
+       image_header_t *hdr = &header;
+       tplink_image_header_t *tpl_hdr;
+
+       /*
+        * By default don't verify data CRC checksum,
+        * but allow to enable it, using environment
+        **/
+       s = getenv("verify_data");
+       verify = (s && (*s == 'y')) ? 1 : 0;
+
+       if (argc < 2) {
+               addr = load_addr;
+       } else {
+               addr = simple_strtoul(argv[1], NULL, 16);
        }
 
-       switch(hdr->ih_arch){
-               case IH_CPU_INVALID:
-                       arch = "Invalid CPU";
-                       break;
-               case IH_CPU_ALPHA:
-                       arch = "Alpha";
-                       break;
-               case IH_CPU_ARM:
-                       arch = "ARM";
-                       break;
-               case IH_CPU_I386:
-                       arch = "Intel x86";
-                       break;
-               case IH_CPU_IA64:
-                       arch = "IA64";
-                       break;
-               case IH_CPU_MIPS:
-                       arch = "MIPS";
-                       break;
-               case IH_CPU_MIPS64:
-                       arch = "MIPS 64 Bit";
-                       break;
-               case IH_CPU_PPC:
-                       arch = "PowerPC";
-                       break;
-               case IH_CPU_S390:
-                       arch = "IBM S390";
-                       break;
-               case IH_CPU_SH:
-                       arch = "SuperH";
-                       break;
-               case IH_CPU_SPARC:
-                       arch = "SPARC";
-                       break;
-               case IH_CPU_SPARC64:
-                       arch = "SPARC 64 Bit";
-                       break;
-               case IH_CPU_M68K:
-                       arch = "M68K";
-                       break;
-               case IH_CPU_MICROBLAZE:
-                       arch = "Microblaze";
-                       break;
-               case IH_CPU_NIOS:
-                       arch = "Nios";
-                       break;
-               case IH_CPU_NIOS2:
-                       arch = "Nios-II";
-                       break;
-               default:
-                       arch = "Unknown Architecture";
-                       break;
+       printf("Booting image from 0x%08lX...\n", addr);
+
+       /* Check what header type we have */
+       memmove(&data, (char *)addr, sizeof(u32));
+       tpl_type = 0;
+
+       switch (ntohl(data)) {
+       case TPL_IH_VERSION_V1:
+               tpl_type = 1;
+
+               tpl_hdr = (tplink_image_header_t *)addr;
+               print_tpl_ih_v1(tpl_hdr);
+
+               /* Convert to general format */
+               tpl_to_uboot_header(hdr, tpl_hdr);
+               break;
+       case IH_MAGIC:
+               print_uboot_ih((image_header_t *)addr);
+               memmove(&header, (char *)addr, sizeof(image_header_t));
+               break;
+       case TPL_IH_VERSION_V2:
+       case TPL_IH_VERSION_V3:
+       default:
+               puts("## Error: unsupported image header\n");
+               return 1;
        }
 
-       switch(hdr->ih_type){
-               case IH_TYPE_INVALID:
-                       type = "Invalid Image";
-                       break;
-               case IH_TYPE_STANDALONE:
-                       type = "Standalone Program";
-                       break;
-               case IH_TYPE_KERNEL:
-                       type = "Kernel Image";
-                       break;
-               case IH_TYPE_RAMDISK:
-                       type = "RAMDisk Image";
-                       break;
-               case IH_TYPE_MULTI:
-                       type = "Multi-File Image";
-                       break;
-               case IH_TYPE_FIRMWARE:
-                       type = "Firmware";
-                       break;
-               case IH_TYPE_SCRIPT:
-                       type = "Script";
-                       break;
-               default:
-                       type = "Unknown Image";
-                       break;
+       /* Always verify header CRC */
+       if (ih_header_crc(hdr, tpl_type) != 0) {
+               puts("## Error: header checksum mismatch!\n");
+               return 1;
        }
 
-       switch(hdr->ih_comp){
-               case IH_COMP_NONE:
-                       comp = "uncompressed";
-                       break;
-               case IH_COMP_GZIP:
-                       comp = "gzip compressed";
-                       break;
-               case IH_COMP_BZIP2:
-                       comp = "bzip2 compressed";
-                       break;
-               case IH_COMP_LZMA:
-                       comp = "lzma compressed";
-                       break;
-               default:
-                       comp = "unknown compression";
-                       break;
+       /* And data if enabled */
+       if (tpl_type) {
+               data = addr + sizeof(tplink_image_header_t);
+       } else {
+               data = addr + sizeof(image_header_t);
        }
 
-       printf("%s %s %s (%s)", arch, os, type, comp);
-}
+       if (ih_data_crc(data, hdr, tpl_type, verify) != 0) {
+               puts("## Error: data checksum mismatch!\n");
+               return 1;
+       }
 
-void print_image_hdr(image_header_t *hdr){
-#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
-       time_t timestamp = (time_t)ntohl(hdr->ih_time);
-       struct rtc_time tm;
-#endif
+       puts("\n");
 
-       printf("\n   Image name:   %.*s\n", IH_NMLEN, hdr->ih_name);
+       len = ntohl(hdr->ih_size);
+       len_ptr = (u32 *)data;
 
-#if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
-       to_tm(timestamp, &tm);
-       printf("   Created:      %4d-%02d-%02d  %2d:%02d:%02d UTC\n", tm.tm_year, tm.tm_mon, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec);
-#endif /* CFG_CMD_DATE, CONFIG_TIMESTAMP */
+       /* We support only MIPS */
+       if (hdr->ih_arch != IH_CPU_MIPS) {
+               puts("## Error: unsupported architecture!\n");
+               return 1;
+       }
+
+       /* Image type... */
+       switch (hdr->ih_type) {
+       case IH_TYPE_KERNEL:
+               break;
+       case IH_TYPE_MULTI:
+               /* OS kernel is always in first image */
+               len = ntohl(len_ptr[0]);
+               data += 8;
+
+               /* Move over list to first image */
+               for (i = 1; len_ptr[i]; ++i)
+                       data += 4;
+
+               break;
+       default:
+               puts("## Error: unsupported image type!\n");
+               return 1;
+       }
 
-       puts("   Image type:   ");
-       print_type(hdr);
+       /*
+        * We have reached the point of no return: we are going to
+        * overwrite all exception vector code, so we cannot easily
+        * recover from any failures any more...
+        */
 
-       printf("\n   Data size:    %d Bytes = ", ntohl(hdr->ih_size));
-       print_size(ntohl(hdr->ih_size), "\n");
+#ifdef CONFIG_NETCONSOLE
+       /*
+       * Stop the ethernet stack if NetConsole could have
+       * left it up
+       */
+       puts("Stopping network... ");
+       eth_halt();
+       puts("OK!\n");
+#endif
 
-       printf("   Load address: 0x%08X\n   Entry point:  0x%08X\n", ntohl(hdr->ih_load), ntohl(hdr->ih_ep));
+       /* TODO: should we flush caches for kernel? */
+       /*
+        * Flush everything, restore caches for linux
+        */
+       //mips_cache_flush();
+       //mips_icache_flush_ix();
+
+       /* XXX - this causes problems when booting from flash */
+       /* dcache_disable(); */
 
-       if(hdr->ih_type == IH_TYPE_MULTI){
-               int i;
-               ulong len;
-               ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
+       /* Compression type... */
+       switch (hdr->ih_comp) {
+       case IH_COMP_LZMA:
+               printf("Uncompressing %s... ", ih_img_type(hdr->ih_type));
 
-               puts("   Contents:\n");
+               /* Try to extract LZMA data... */
+               i = lzma_inflate((u8 *)data, len,
+                       (u8 *)ntohl(hdr->ih_load), (int *)&unc_len);
 
-               for(i = 0; (len = ntohl(*len_ptr)); ++i, ++len_ptr){
-                       printf("      Image %d: %8ld Bytes = ", i, len);
-                       print_size(len, "\n");
+               /* TODO: more verbose LZMA errors */
+               if (i != LZMA_RESULT_OK) {
+                       puts("ERROR\n");
+                       printf("## Error: LZMA error '%d'!\n", i);
+                       return 1;
                }
+
+               puts("OK!\n");
+               break;
+       default:
+               printf("## Error: unsupported compression type '%s'!\n",
+                       ih_comp_type(hdr->ih_comp));
+
+               return 1;
        }
 
-       puts("\n");
-}
-#else
-void print_image_hdr(tplink_image_header_t *hdr){
-       printf("\n   Image name:   %.*s %.*s\n", SIG_LEN, hdr->signiture_1, SIG_LEN_2, hdr->signiture_2);
-         puts("   Image type:   MIPS Linux Kernel Image (lzma compressed)\n");
-       printf("   Data size:    %d Bytes = ", ntohl(hdr->kernelLen));
-       print_size(ntohl(hdr->kernelLen), "\n");
-       printf("   Load address: 0x%08X\n   Entry point:  0x%08X\n\n", ntohl(hdr->kernelTextAddr), ntohl(hdr->kernelEntryPoint));
+#ifdef CONFIG_SILENT_CONSOLE
+       fixup_silent_linux();
+#endif
+
+       do_bootm_linux(cmdtp, flag, argc, argv);
+
+       return 1;
 }
-#endif /* !CONFIG_TPLINK_IMAGE_HEADER */
+
+U_BOOT_CMD(bootm, 2, 1, do_bootm,
+       "boot application image from memory\n", "[addr]\n"
+       "\t- boot application image stored in memory at address 'addr'\n");
 
 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
-int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
-       int rcode = 0;
+int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
 #ifndef CFG_HUSH_PARSER
-       if(run_command (getenv ("bootcmd"), flag) < 0){
-               rcode = 1;
-       }
+       if (run_command(getenv("bootcmd"), flag) < 0)
+               return 1;
 #else
-       if(parse_string_outer(getenv("bootcmd"), FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0){
-               rcode = 1;
-       }
+       if (parse_string_outer(getenv("bootcmd"),
+               FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
+               return 1;
 #endif
-       return(rcode);
-}
-
-U_BOOT_CMD(boot, 1, 1, do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);
 
-/* keep old command name "bootd" for backward compatibility */
-U_BOOT_CMD(bootd, 1, 1, do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);
+       return 0;
+}
 
+U_BOOT_CMD(boot, 1, 1, do_bootd, "boot default, run 'bootcmd'\n", NULL);
 #endif /* CONFIG_COMMANDS & CFG_CMD_BOOTD */
 
 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
-int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
-       ulong addr;
-       int rcode = 0;
+int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
+{
+       int tpl_type;
+       u32 addr, data;
+       image_header_t *hdr = &header;
+       tplink_image_header_t *tpl_hdr;
 
-       if (argc == 2){
+       tpl_type = 0;
+
+       if (argc == 2) {
                addr = simple_strtoul(argv[1], NULL, 16);
-               return image_info(addr);
        } else {
 #ifdef CFG_LONGHELP
-               if(cmdtp->help != NULL){
+               if (cmdtp->help != NULL) {
                        printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
                } else {
                        printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
@@ -431,52 +589,56 @@ int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
 #else
                printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
 #endif
-               return(1);
+               return 1;
        }
 
-       return(rcode);
-}
-
-static int image_info(ulong addr){
-       ulong data, len, checksum;
-       image_header_t *hdr = &header;
-
        printf("\nChecking image at 0x%08lX...\n", addr);
 
-       /* Copy header so we can blank CRC field for re-calculation */
-       memmove(&header, (char *)addr, sizeof(image_header_t));
-
-       data = (ulong)&header;
-       len  = sizeof(image_header_t);
-
-       checksum = ntohl(hdr->ih_hcrc);
-       hdr->ih_hcrc = 0;
-
-       if(tinf_crc32((uchar *)data, len) != checksum){
-               puts("## Error: bad header checksum!\n");
+       /* Check what header type we have */
+       memmove(&data, (char *)addr, sizeof(u32));
+
+       switch (ntohl(data)) {
+       case TPL_IH_VERSION_V1:
+               tpl_type = 1;
+
+               tpl_hdr = (tplink_image_header_t *)addr;
+               print_tpl_ih_v1(tpl_hdr);
+               break;
+       case IH_MAGIC:
+               print_uboot_ih((image_header_t *)addr);
+               memmove(&header, (char *)addr, sizeof(image_header_t));
+               break;
+       case TPL_IH_VERSION_V2:
+       case TPL_IH_VERSION_V3:
+       default:
+               puts("## Error: unsupported image header\n");
                return 1;
        }
 
-       /* for multi-file images we need the data part, too */
-       print_image_hdr((image_header_t *)addr);
-
-       data = addr + sizeof(image_header_t);
-       len  = ntohl(hdr->ih_size);
+       /* Always verify header CRC */
+       if (ih_header_crc(hdr, tpl_type) != 0) {
+               puts("## Error: header checksum mismatch!\n");
+               return 1;
+       }
 
-       puts("   Verifying checksum... ");
+       /* And data.. here always */
+       if (tpl_type) {
+               data = addr + sizeof(tplink_image_header_t);
+       } else {
+               data = addr + sizeof(image_header_t);
+       }
 
-       if(tinf_crc32((uchar *)data, len) != ntohl(hdr->ih_dcrc)){
-               puts("bad data CRC!\n");
-               return(1);
+       if (ih_data_crc(data, hdr, tpl_type, 1) != 0) {
+               puts("## Error: data checksum mismatch!\n");
+               return 1;
        }
 
-       puts("OK!\n\n");
+       puts("\n");
 
-       return(0);
+       return 0;
 }
 
-U_BOOT_CMD(iminfo, 2, 1, do_iminfo, "print firmware header\n", "address\n"
-               "\t- print header information for firmware image startting at address 'address'\n"
-);
-
-#endif /* CFG_CMD_IMI */
+U_BOOT_CMD(iminfo, 2, 1, do_iminfo,
+       "print firmware header\n", "address\n"
+       "\t- print header information for image at 'address'\n");
+#endif /* CFG_CMD_IMI */
index 0a008274cef2e785bbe081d7da6a46a5338ade88..5873fa4bf0fa80a81b776d1f7020bd2c13103294 100644 (file)
@@ -199,18 +199,8 @@ void flash_perror (int);
 /* common/cmd_autoscript.c */
 int    autoscript (ulong addr);
 
-/*
- * Only TP-Link OFW and OpenWrt for TP-Link routers
- * use different (simply) image header
- */
-#ifdef CONFIG_TPLINK_IMAGE_HEADER
-#include "tpLinuxTag.h"
-void print_image_hdr(tplink_image_header_t *hdr);
-#else
-void print_image_hdr(image_header_t *hdr);
-#endif /* CONFIG_TPLINK_IMAGE_HEADER */
-
-extern ulong load_addr;                /* Default Load Address */
+/* Default Load Address */
+extern u32 load_addr;
 
 /* common/cmd_nvedit.c */
 int            env_init     (void);
diff --git a/u-boot/include/tpLinuxTag.h b/u-boot/include/tpLinuxTag.h
deleted file mode 100644 (file)
index 425560a..0000000
+++ /dev/null
@@ -1,60 +0,0 @@
-
-/**************************************************************************************
-* File Name  : tpLinuxTag.h
-*
-* Description: add tag with validation system to the firmware image file to be uploaded
-*              via http
-*
-* Created    : 16Sep07,        Liang Qiming
-**************************************************************************************/
-
-#ifndef _TP_LINUX_TAG_H_
-#define _TP_LINUX_TAG_H_
-
-/*
- * File tag (head) structure all is in clear text
- * except validationTokens (crc, md5, sha1, etc).
- *
- * Total: 128 unsigned chars
- */
-#define TAG_LEN                        512
-#define SIG_LEN                        24
-#define SIG_LEN_2              12 // Original second SIG = 20 is now devided into 14 for SIG_LEN_2 and 6 for CHIP_ID
-#define CHIP_ID_LEN            8
-#define TOKEN_LEN              20
-#define BOARD_ID_LEN   16
-
-/*
- * TAG for downloadable image (kernel plus file system)
- * integer in the structure is stored in Network-Byte order (BIG-endian)
- */
-typedef struct _tplink_image_header_t {
-       unsigned long   tagVersion;
-    char                       signiture_1[SIG_LEN];                           // text line for company info
-       char                    signiture_2[SIG_LEN_2];                         // additional info (can be version number)
-    char                       chipId[CHIP_ID_LEN];                            // chip id
-    char                       boardId[BOARD_ID_LEN];                          // board id
-    unsigned long      productId;                                                      // product id
-    unsigned long      productVer;                                                     // product version
-    unsigned long      reserved1;                                                      // reserved for future
-
-    unsigned char      imageValidationToken[TOKEN_LEN];        // image validation token - md5 checksum
-    unsigned char      kernelValidationToken[TOKEN_LEN];       // kernel+tag validation token - md5 checksum
-
-       unsigned long   kernelTextAddr;                                         // text section address of kernel
-       unsigned long   kernelEntryPoint;                                       // entry point address of kernel
-       
-       unsigned long   totalImageLen;                                          // the sum of kernelLen+rootfsLen+tagLen
-
-       unsigned long   kernelAddress;                                          // starting address (offset from the beginning of FILE_TAG) of kernel image
-       unsigned long   kernelLen;                                                      // length of kernel image
-
-       unsigned long   rootfsAddress;                                          // starting address (offset) of filesystem image
-       unsigned long   rootfsLen;                                                      // length of filesystem image
-
-       unsigned long   bootloaderAddress;                                      // starting address (offset) of boot loader image
-       unsigned long   bootloaderLen;                                          // length of boot loader image
-       
-} tplink_image_header_t;
-
-#endif /* ifndef _TP_LINUX_TAG_H_ */
diff --git a/u-boot/include/tplink_image.h b/u-boot/include/tplink_image.h
new file mode 100644 (file)
index 0000000..2d4e9f0
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 Piotr Dymacz <piotr@dymacz.pl>
+ *
+ * Based on mktplinkfw.c from OpenWrt
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef __TPLINK_IMAGE_H__
+#define __TPLINK_IMAGE_H__
+
+#define TPL_IH_VERSION_V1      0x01000000
+#define TPL_IH_VERSION_V2      0x02000000
+#define TPL_IH_VERSION_V3      0x03000000
+
+#define MD5SUM_LEN     16
+
+/* For v1 version of header version */
+typedef struct tplink_image_header {           /* ofs (size): what                     */
+       uint32_t ih_version;                    /* 0x0    (4): header version           */
+       char     ih_vendor[24];                 /* 0x4   (24): vendor name (text)       */
+       char     ih_info[36];                   /* 0x1C  (36): other info like version  */
+       uint32_t ih_hw_id;                      /* 0x40   (4): hardware ID              */
+       uint32_t ih_hw_ver;                     /* 0x44   (4): hardware version         */
+       uint32_t ih_region;                     /* 0x48   (4): region code              */
+       uint8_t  ih_md5sum1[MD5SUM_LEN];        /* 0x4C  (16): MD5 sum #1               */
+       uint32_t ih_ignore1;                    /* 0x5C   (4): unknown                  */
+       uint8_t  ih_md5sum2[MD5SUM_LEN];        /* 0x60  (16): MD5 sum #2               */
+       uint32_t ih_ignore2;                    /* 0x70   (4): unknown                  */
+       uint32_t ih_kernel_load;                /* 0x74   (4): kernel load address      */
+       uint32_t ih_kernel_ep;                  /* 0x78   (4): kernel entry point       */
+       uint32_t ih_fw_len;                     /* 0x7C   (4): image size (with header) */
+       uint32_t ih_kernel_ofs;                 /* 0x80   (4): kernel data offset       */
+       uint32_t ih_kernel_len;                 /* 0x84   (4): kernel data size         */
+       uint32_t ih_rootfs_ofs;                 /* 0x88   (4): rootfs data offset       */
+       uint32_t ih_rootfs_len;                 /* 0x8C   (4): rootfs data size         */
+       uint32_t ih_boot_ofs;                   /* 0x90   (4): bootloader data offset   */
+       uint32_t ih_boot_len;                   /* 0x94   (4): bootloader data size     */
+       uint16_t ih_fw_ver_hi;                  /* 0x98   (2): firmware version hi      */
+       uint16_t ih_fw_ver_mid;                 /* 0x9A   (2): firmware version mid     */
+       uint16_t ih_fw_ver_lo;                  /* 0x9C   (2): firmware version lo      */
+       uint8_t  ih_pad[354];                   /* 0x9E (354): padding, not used...     */
+} tplink_image_header_t;
+
+#endif /* __TPLINK_IMAGE_H__ */