Support also version v2 of TP-Link header
[oweals/u-boot_mod.git] / u-boot / common / cmd_bootm.c
1 /*
2  * Copyright (C) 2016 Piotr Dymacz <piotr@dymacz.pl>
3  * Copyright (C) 2000-2006 Wolfgang Denk, DENX Software Engineering, <wd@denx.de>
4  *
5  * SPDX-License-Identifier: GPL-2.0
6  */
7
8 /*
9  * Boot support
10  */
11 #include <common.h>
12 #include <command.h>
13 #include <image.h>
14 #include <tplink_image.h>
15 #include <malloc.h>
16 #include <LzmaWrapper.h>
17 #include <environment.h>
18 #include <asm/byteorder.h>
19 #include <tinf.h>
20
21 #ifdef CFG_HUSH_PARSER
22 #include <hush.h>
23 #endif
24
25 #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
26 #include <rtc.h>
27 #endif
28
29 DECLARE_GLOBAL_DATA_PTR;
30
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);
34
35 /* U-Boot type image header */
36 image_header_t header;
37
38 /* Default load address */
39 u32 load_addr = CFG_LOAD_ADDR;
40
41 #define TPL_ALIGN_SIZE          21
42 #define UBOOT_ALIGN_SIZE        14
43
44 /*
45  * Clears console variable from command line
46  */
47 #ifdef CONFIG_SILENT_CONSOLE
48 static void fixup_silent_linux(void)
49 {
50         char buf[256];
51         char *cmdline, *end, *start;
52
53         /* Only fix cmdline when requested */
54         if (!(gd->flags & GD_FLG_SILENT)) {
55                 return;
56         }
57
58         cmdline = getenv("bootargs");
59
60         if (cmdline) {
61                 if ((start = strstr(cmdline, "console=")) != NULL) {
62                         end = strchr(start, ' ');
63                         strncpy(buf, cmdline, (start - cmdline + 8));
64
65                         if (end) {
66                                 strcpy(buf + (start - cmdline + 8), end);
67                         } else {
68                                 buf[start - cmdline + 8] = '\0';
69                         }
70                 } else {
71                         strcpy(buf, cmdline);
72                         strcat(buf, " console=");
73                 }
74         } else {
75                 strcpy(buf, "console=");
76         }
77
78         setenv("bootargs", buf);
79 }
80 #endif /* CONFIG_SILENT_CONSOLE */
81
82 /*
83  * Prints information about TP-Link
84  * firmware format from header
85  */
86 static void print_tpl_ih_v1(tplink_image_header_t *hdr)
87 {
88         puts("\n");
89
90         /* Image/vendor name */
91         printf("   %-*s ", TPL_ALIGN_SIZE, "Vendor/image name:");
92         printf("%.*s %.*s\n",
93                 sizeof(hdr->ih_vendor), hdr->ih_vendor,
94                 sizeof(hdr->ih_info), hdr->ih_info);
95
96         /* Version (for vendor firmware only) */
97         if (hdr->ih_fw_ver_hi > 0) {
98                 printf("   %-*s ", TPL_ALIGN_SIZE, "Firmware version:");
99                 printf("%d.%d.%d\n",
100                         ntohl(hdr->ih_fw_ver_hi),
101                         ntohl(hdr->ih_fw_ver_mid),
102                         ntohl(hdr->ih_fw_ver_lo));
103         }
104
105         /* Hardware id */
106         printf("   %-*s ", TPL_ALIGN_SIZE, "Hardware ID:");
107         printf("0x%X\n", ntohl(hdr->ih_hw_id));
108
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));
113
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));
117
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));
121
122         printf("   %-*s ", TPL_ALIGN_SIZE, "Kernel load address:");
123         printf("0x%08X\n", ntohl(hdr->ih_kernel_load));
124
125         printf("   %-*s ", TPL_ALIGN_SIZE, "Kernel entry point:");
126         printf("0x%08X\n", ntohl(hdr->ih_kernel_ep));
127
128         /* TODO: MD5 sum verify */
129
130         puts("\n");
131 }
132
133 /*
134  * Returns image type in text
135  */
136 static char *ih_img_type(uint8_t img)
137 {
138         switch (img) {
139         case IH_TYPE_KERNEL:
140                 return "Kernel";
141         case IH_TYPE_MULTI:
142                 return "Multi-File";
143 /*
144         case IH_TYPE_INVALID:
145                 return "Invalid";
146         case IH_TYPE_STANDALONE:
147                 return "Standalone program";
148         case IH_TYPE_RAMDISK:
149                 return "RAMDisk";
150         case IH_TYPE_FIRMWARE:
151                 return "Firmware";
152         case IH_TYPE_SCRIPT:
153                 return "Script";
154 */
155         default:
156                 return "unknown";
157         }
158 }
159
160 /*
161  * Returns architecture type in text
162  */
163 static char *ih_arch_type(uint8_t arch)
164 {
165         switch (arch) {
166         case IH_CPU_MIPS:
167                 return "MIPS";
168 /*
169         case IH_CPU_INVALID:
170                 return "Invalid CPU";
171         case IH_CPU_ALPHA:
172                 return "Alpha";
173         case IH_CPU_ARM:
174                 return "ARM";
175         case IH_CPU_I386:
176                 return "Intel x86";
177         case IH_CPU_IA64:
178                 return "IA64";
179         case IH_CPU_MIPS64:
180                 return "MIPS 64-bit";
181         case IH_CPU_PPC:
182                 return "PowerPC";
183         case IH_CPU_S390:
184                 return "IBM S390";
185         case IH_CPU_SH:
186                 return "SuperH";
187         case IH_CPU_SPARC:
188                 return "SPARC";
189         case IH_CPU_SPARC64:
190                 return "SPARC 64-bit";
191         case IH_CPU_M68K:
192                 return "M68K";
193         case IH_CPU_MICROBLAZE:
194                 return "Microblaze";
195         case IH_CPU_NIOS:
196                 return "Nios";
197         case IH_CPU_NIOS2:
198                 return "Nios-II";
199 */
200         default:
201                 return "unknown";
202         }
203 }
204
205 /*
206  * Returns compression type in text
207  */
208 static char *ih_comp_type(uint8_t comp)
209 {
210         switch (comp) {
211         case IH_COMP_LZMA:
212                 return "LZMA";
213 /*
214         case IH_COMP_NONE:
215                 return "none";
216         case IH_COMP_GZIP:
217                 return "GZIP";
218         case IH_COMP_BZIP2:
219                 return "BZIP2";
220 */
221         default:
222                 return "unknown";
223         }
224 }
225
226 /*
227  * Returns operating system type in text
228  */
229 static char *ih_os_type(uint8_t os)
230 {
231         switch (os) {
232         case IH_OS_LINUX:
233                 return "Linux";
234 /*
235         case IH_OS_INVALID:
236                 return "Invalid OS";
237         case IH_OS_NETBSD:
238                 return "NetBSD";
239         case IH_OS_VXWORKS:
240                 return "VxWorks";
241         case IH_OS_QNX:
242                 return "QNX";
243         case IH_OS_U_BOOT:
244                 return "U-Boot";
245         case IH_OS_RTEMS:
246                 return "RTEMS";
247 */
248         default:
249                 return "unknown";
250         }
251 }
252
253 /*
254  * Prints information about standard
255  * U-Boot image format from header
256  */
257 static void print_uboot_ih(image_header_t *hdr)
258 {
259         int i;
260         u32 len;
261         u32 *len_ptr;
262 #if defined(CONFIG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
263         struct rtc_time tm;
264         time_t timestamp = (time_t)ntohl(hdr->ih_time);
265 #endif
266
267         puts("\n");
268
269         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Image name:");
270         printf("%.*s\n", sizeof(hdr->ih_name), hdr->ih_name);
271
272 #if defined(CONFIG_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);
278 #endif
279
280         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Architecture:");
281         printf("%s\n", ih_arch_type(hdr->ih_arch));
282
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));
285
286         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Compression:");
287         printf("%s\n", ih_comp_type(hdr->ih_comp));
288
289         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Data size:");
290         print_size(ntohl(hdr->ih_size), " ");
291         printf("(%d bytes)\n", ntohl(hdr->ih_size));
292
293         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Load address:");
294         printf("0x%08X\n", ntohl(hdr->ih_load));
295
296         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Entry point:");
297         printf("0x%08X\n", ntohl(hdr->ih_ep));
298
299         if (hdr->ih_type == IH_TYPE_MULTI) {
300                 len_ptr = (u32 *)((u32)hdr + sizeof(image_header_t));
301
302                 printf("\n   %-*s\n", UBOOT_ALIGN_SIZE, "Multi-File:");
303
304                 for (i = 0; (len = ntohl(*len_ptr)); ++i, ++len_ptr) {
305                         puts("   > ");
306                         print_size(len, " ");
307                         printf("(%d bytes)\n", len);
308                 }
309         }
310
311         puts("\n");
312 }
313
314 /*
315  * Verifies U-Boot image data checksum
316  */
317 static int ih_data_crc(u32 addr, image_header_t *hdr, int tpl_type, int verify)
318 {
319         int ret = 0;
320
321         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Data CRC...");
322
323         if (tpl_type == 0 && verify == 1) {
324                 if (tinf_crc32((u8 *)addr, ntohl(hdr->ih_size))
325                     != ntohl(hdr->ih_dcrc)) {
326                         puts("ERROR\n\n");
327                         ret = 1;
328                 } else {
329                         puts("OK!\n");
330                 }
331         } else {
332                 puts("skipped\n");
333         }
334
335         return ret;
336 }
337
338 /*
339  * Verifies U-Boot image header checksum
340  */
341 static int ih_header_crc(image_header_t *hdr, int tpl_type)
342 {
343         u32 crc;
344         int ret = 0;
345
346         printf("   %-*s ", UBOOT_ALIGN_SIZE, "Header CRC...");
347
348         if (tpl_type == 0) {
349                 crc = ntohl(hdr->ih_hcrc);
350                 hdr->ih_hcrc = 0;
351
352                 if (tinf_crc32((u8 *)hdr, sizeof(image_header_t)) != crc) {
353                         puts("ERROR\n\n");
354                         ret = 1;
355                 } else {
356                         puts("OK!\n");
357                 }
358
359                 hdr->ih_hcrc = crc;
360         } else {
361                 puts("skipped\n");
362         }
363
364         return ret;
365 }
366
367 /*
368  * Converts TP-Link header to stanard
369  * U-Boot image format header
370  */
371 static void tpl_to_uboot_header(image_header_t *hdr,
372                                 tplink_image_header_t *tpl_hdr)
373 {
374         memset(hdr, 0, sizeof(image_header_t));
375
376         /* Set only needed values */
377         hdr->ih_hcrc = 0;
378         hdr->ih_dcrc = 0;
379
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);
383
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;
388 }
389
390 int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
391 {
392         char *s;
393         u32 *len_ptr;
394         u32 addr, data, len;
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;
399
400         /*
401          * By default don't verify data CRC checksum,
402          * but allow to enable it, using environment
403          **/
404         s = getenv("verify_data");
405         verify = (s && (*s == 'y')) ? 1 : 0;
406
407         if (argc < 2) {
408                 addr = load_addr;
409         } else {
410                 addr = simple_strtoul(argv[1], NULL, 16);
411         }
412
413         printf("Booting image from 0x%08lX...\n", addr);
414
415         /* Check what header type we have */
416         memmove(&data, (char *)addr, sizeof(u32));
417         tpl_type = 0;
418
419         switch (ntohl(data)) {
420         case TPL_IH_VERSION_V1:
421         case TPL_IH_VERSION_V2:
422                 tpl_type = 1;
423
424                 tpl_hdr = (tplink_image_header_t *)addr;
425                 print_tpl_ih_v1(tpl_hdr);
426
427                 /* Convert to general format */
428                 tpl_to_uboot_header(hdr, tpl_hdr);
429                 break;
430         case IH_MAGIC:
431                 print_uboot_ih((image_header_t *)addr);
432                 memmove(&header, (char *)addr, sizeof(image_header_t));
433                 break;
434         case TPL_IH_VERSION_V3:
435         default:
436                 printf_err("unsupported image header\n");
437                 return 1;
438         }
439
440         /* Always verify header CRC */
441         if (ih_header_crc(hdr, tpl_type) != 0) {
442                 printf_err("header checksum mismatch!\n");
443                 return 1;
444         }
445
446         /* And data if enabled */
447         if (tpl_type) {
448                 data = addr + sizeof(tplink_image_header_t);
449         } else {
450                 data = addr + sizeof(image_header_t);
451         }
452
453         if (ih_data_crc(data, hdr, tpl_type, verify) != 0) {
454                 printf_err("data checksum mismatch!\n");
455                 return 1;
456         }
457
458         puts("\n");
459
460         len = ntohl(hdr->ih_size);
461         len_ptr = (u32 *)data;
462
463         /* We support only MIPS */
464         if (hdr->ih_arch != IH_CPU_MIPS) {
465                 printf_err("unsupported architecture!\n");
466                 return 1;
467         }
468
469         /* Image type... */
470         switch (hdr->ih_type) {
471         case IH_TYPE_KERNEL:
472                 break;
473         case IH_TYPE_MULTI:
474                 /* OS kernel is always in first image */
475                 len = ntohl(len_ptr[0]);
476                 data += 8;
477
478                 /* Move over list to first image */
479                 for (i = 1; len_ptr[i]; ++i)
480                         data += 4;
481
482                 break;
483         default:
484                 printf_err("unsupported image type!\n");
485                 return 1;
486         }
487
488         /*
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...
492          */
493
494 #ifdef CONFIG_NETCONSOLE
495         /*
496         * Stop the ethernet stack if NetConsole could have
497         * left it up
498         */
499         puts("Stopping network... ");
500         eth_halt();
501         puts("OK!\n");
502 #endif
503
504         /* TODO: should we flush caches for kernel? */
505         /*
506          * Flush everything, restore caches for linux
507          */
508         //mips_cache_flush();
509         //mips_icache_flush_ix();
510
511         /* XXX - this causes problems when booting from flash */
512         /* dcache_disable(); */
513
514         /* Compression type... */
515         switch (hdr->ih_comp) {
516         case IH_COMP_LZMA:
517                 printf("Uncompressing %s... ", ih_img_type(hdr->ih_type));
518
519                 /* Try to extract LZMA data... */
520                 i = lzma_inflate((u8 *)data, len,
521                         (u8 *)ntohl(hdr->ih_load), (int *)&unc_len);
522
523                 /* TODO: more verbose LZMA errors */
524                 if (i != LZMA_RESULT_OK) {
525                         puts("ERROR\n");
526                         printf_err("LZMA error '%d'!\n", i);
527                         return 1;
528                 }
529
530                 puts("OK!\n");
531                 break;
532         default:
533                 printf_err("unsupported compression type '%s'!\n",
534                            ih_comp_type(hdr->ih_comp));
535
536                 return 1;
537         }
538
539 #ifdef CONFIG_SILENT_CONSOLE
540         fixup_silent_linux();
541 #endif
542
543         do_bootm_linux(cmdtp, flag, argc, argv);
544
545         return 1;
546 }
547
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");
551
552 #if defined(CONFIG_CMD_BOOTD)
553 int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
554 {
555 #ifndef CFG_HUSH_PARSER
556         if (run_command(getenv("bootcmd"), flag) < 0)
557                 return 1;
558 #else
559         if (parse_string_outer(getenv("bootcmd"),
560                 FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)
561                 return 1;
562 #endif
563
564         return 0;
565 }
566
567 U_BOOT_CMD(boot, 1, 1, do_bootd, "boot default, run 'bootcmd'\n", NULL);
568 #endif /* CONFIG_CMD_BOOTD */
569
570 #if defined(CONFIG_CMD_IMI)
571 int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])
572 {
573         int tpl_type;
574         u32 addr, data;
575         image_header_t *hdr = &header;
576         tplink_image_header_t *tpl_hdr;
577
578         tpl_type = 0;
579
580         if (argc == 2) {
581                 addr = simple_strtoul(argv[1], NULL, 16);
582         } else {
583                 print_cmd_help(cmdtp);
584                 return 1;
585         }
586
587         printf("\nChecking image at 0x%08lX...\n", addr);
588
589         /* Check what header type we have */
590         memmove(&data, (char *)addr, sizeof(u32));
591
592         switch (ntohl(data)) {
593         case TPL_IH_VERSION_V1:
594         case TPL_IH_VERSION_V2:
595                 tpl_type = 1;
596
597                 tpl_hdr = (tplink_image_header_t *)addr;
598                 print_tpl_ih_v1(tpl_hdr);
599                 break;
600         case IH_MAGIC:
601                 print_uboot_ih((image_header_t *)addr);
602                 memmove(&header, (char *)addr, sizeof(image_header_t));
603                 break;
604         case TPL_IH_VERSION_V3:
605         default:
606                 printf_err("unsupported image header\n");
607                 return 1;
608         }
609
610         /* Always verify header CRC */
611         if (ih_header_crc(hdr, tpl_type) != 0) {
612                 printf_err("header checksum mismatch!\n");
613                 return 1;
614         }
615
616         /* And data.. here always */
617         if (tpl_type) {
618                 data = addr + sizeof(tplink_image_header_t);
619         } else {
620                 data = addr + sizeof(image_header_t);
621         }
622
623         if (ih_data_crc(data, hdr, tpl_type, 1) != 0) {
624                 printf_err("data checksum mismatch!\n");
625                 return 1;
626         }
627
628         puts("\n");
629
630         return 0;
631 }
632
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 /* CONFIG_CMD_IMI */