4877713d45af28fbe98b38f147dd354a064e0172
[oweals/u-boot_mod.git] / u-boot / common / cmd_bootm.c
1 /*
2  * (C) Copyright 2000-2006
3  * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
4  *
5  * See file CREDITS for list of people who contributed to this
6  * project.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU General Public License as
10  * published by the Free Software Foundation; either version 2 of
11  * the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
21  * MA 02111-1307 USA
22  */
23
24 /*
25  * Boot support
26  */
27 #include <common.h>
28 #include <command.h>
29 #include <image.h>
30 #include <malloc.h>
31 #include <zlib.h>
32 #include <bzlib.h>
33 #include <LzmaWrapper.h>
34 #include <environment.h>
35 #include <asm/byteorder.h>
36
37 DECLARE_GLOBAL_DATA_PTR;
38
39 #ifdef CFG_HUSH_PARSER
40 #include <hush.h>
41 #endif
42
43 /* cmd_boot.c */
44 extern int do_reset(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
45
46 /* net.c */
47 extern void eth_halt(void);
48
49 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
50 #include <rtc.h>
51 #endif
52
53 /*
54  *  Continue booting an OS image; caller already has:
55  *  - copied image header to global variable `header'
56  *  - checked header magic number, checksums (both header & image),
57  *  - verified image architecture (PPC) and type (KERNEL or MULTI),
58  *  - loaded (first part of) image to header load address,
59  *  - disabled interrupts.
60  */
61 extern void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
62
63 #ifdef CONFIG_SILENT_CONSOLE
64 static void fixup_silent_linux(void);
65 #endif
66
67 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
68 static int image_info(unsigned long addr);
69 #endif
70
71 image_header_t header;
72 ulong load_addr = CFG_LOAD_ADDR; /* default load address */
73
74 #if !defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) && \
75         !defined(CONFIG_FOR_DLINK_DIR505_A1)     && \
76         !defined(CONFIG_FOR_DRAGINO_V2)          && \
77         !defined(CONFIG_FOR_MESH_POTATO_V2)      && \
78         !defined(CONFIG_FOR_BSB)
79 void fake_image_header(image_header_t *hdr, tplink_image_header_t *tpl_hdr){
80         memset(hdr, 0, sizeof(image_header_t));
81
82         /* Build new header */
83         hdr->ih_magic   = htonl(IH_MAGIC);
84         hdr->ih_hcrc    = 0;
85         hdr->ih_time    = 0;
86         hdr->ih_size    = htonl(tpl_hdr->kernelLen);
87         hdr->ih_load    = htonl(tpl_hdr->kernelTextAddr);
88         hdr->ih_ep              = htonl(tpl_hdr->kernelEntryPoint);
89         hdr->ih_dcrc    = 0;
90         hdr->ih_os              = IH_OS_LINUX;
91         hdr->ih_arch    = IH_CPU_MIPS;
92         hdr->ih_type    = IH_TYPE_KERNEL;
93         hdr->ih_comp    = IH_COMP_LZMA;
94
95         strncpy((char *)hdr->ih_name, (char *)tpl_hdr->signiture_1, IH_NMLEN);
96 }
97 #endif /* if !defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) && !defined(CONFIG_FOR_DLINK_DIR505_A1) && !defined(CONFIG_FOR_DRAGINO_V2) && !defined(CONFIG_FOR_MESH_POTATO_V2) && !defined(CONFIG_FOR_BSB) */
98
99 int do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
100         ulong addr, data, len;
101         uint unc_len = CFG_BOOTM_LEN;
102         int i;
103         image_header_t *hdr = &header;
104 #if !defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) && \
105         !defined(CONFIG_FOR_DLINK_DIR505_A1)     && \
106         !defined(CONFIG_FOR_DRAGINO_V2)          && \
107         !defined(CONFIG_FOR_MESH_POTATO_V2)      && \
108         !defined(CONFIG_FOR_BSB)
109         tplink_image_header_t *fileTag;
110 #endif
111
112         if(argc < 2){
113                 addr = load_addr;
114         } else {
115                 addr = simple_strtoul(argv[1], NULL, 16);
116         }
117
118         printf("Booting image at: 0x%08lX\n", addr);
119
120 #if defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) || \
121         defined(CONFIG_FOR_DLINK_DIR505_A1)     || \
122         defined(CONFIG_FOR_DRAGINO_V2)          || \
123         defined(CONFIG_FOR_MESH_POTATO_V2)      || \
124         defined(CONFIG_FOR_BSB)
125         memmove(&header, (char *)addr, sizeof(image_header_t));
126         print_image_hdr(hdr);
127
128         data = addr + sizeof(image_header_t);
129 #else
130         fileTag = (tplink_image_header_t *)addr;
131         print_image_hdr(fileTag);
132
133         fake_image_header(hdr, fileTag);
134
135         data = addr + TAG_LEN;
136 #endif
137
138         len = ntohl(hdr->ih_size);
139
140         /*
141          * We have reached the point of no return: we are going to
142          * overwrite all exception vector code, so we cannot easily
143          * recover from any failures any more...
144          */
145 #ifdef CONFIG_NETCONSOLE
146         /*
147         * Stop the ethernet stack if NetConsole could have
148         * left it up
149         */
150         eth_halt();
151 #endif
152
153 #if defined(CONFIG_AR7100) || defined(CONFIG_AR7240)
154         /*
155          * Flush everything, restore caches for linux
156          */
157         //mips_cache_flush();
158         //mips_icache_flush_ix();
159
160         /* XXX - this causes problems when booting from flash */
161         /* dcache_disable(); */
162 #endif
163
164         /*      case IH_COMP_LZMA:*/
165         puts("Uncompressing kernel image... ");
166
167         i = lzma_inflate((unsigned char *)data, len, (unsigned char*)ntohl(hdr->ih_load), (int *)&unc_len);
168
169         if(i != LZMA_RESULT_OK){
170                 printf("## Error: LZMA error num: %d\n", i);
171                 return(-1);
172         }
173
174         puts("OK!\n");
175
176 #ifdef CONFIG_SILENT_CONSOLE
177         fixup_silent_linux();
178 #endif
179
180         do_bootm_linux(cmdtp, flag, argc, argv);
181
182 #ifdef DEBUG
183         puts("\n## Error: control returned to monitor - resetting...\n");
184         do_reset(cmdtp, flag, argc, argv);
185 #endif
186
187         return(1);
188 }
189
190 U_BOOT_CMD(bootm, 2, 1, do_bootm, "boot application image from memory\n", "[addr]\n"
191 "\t- boot application image stored in memory at address 'addr'\n");
192
193 #ifdef CONFIG_SILENT_CONSOLE
194 static void fixup_silent_linux(){
195         char buf[256], *start, *end;
196         char *cmdline = getenv("bootargs");
197
198         /* Only fix cmdline when requested */
199         if(!(gd->flags & GD_FLG_SILENT)){
200                 return;
201         }
202
203 #ifdef DEBUG
204         printf("before silent fix-up: %s\n", cmdline);
205 #endif
206
207         if(cmdline){
208                 if((start = strstr(cmdline, "console=")) != NULL){
209                         end = strchr(start, ' ');
210                         strncpy(buf, cmdline, (start - cmdline + 8));
211                         if(end){
212                                 strcpy(buf + (start - cmdline + 8), end);
213                         } else {
214                                 buf[start - cmdline + 8] = '\0';
215                         }
216                 } else {
217                         strcpy(buf, cmdline);
218                         strcat(buf, " console=");
219                 }
220         } else {
221                 strcpy(buf, "console=");
222         }
223
224         setenv("bootargs", buf);
225         debug("after silent fix-up: %s\n", buf);
226 }
227 #endif /* CONFIG_SILENT_CONSOLE */
228
229 #if defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) || \
230         defined(CONFIG_FOR_DLINK_DIR505_A1)     || \
231         defined(CONFIG_FOR_DRAGINO_V2)          || \
232         defined(CONFIG_FOR_MESH_POTATO_V2)      || \
233         defined(CONFIG_FOR_BSB)
234 static void print_type(image_header_t *hdr){
235         char *os, *arch, *type, *comp;
236
237         switch(hdr->ih_os){
238                 case IH_OS_INVALID:
239                         os = "Invalid OS";
240                         break;
241                 case IH_OS_NETBSD:
242                         os = "NetBSD";
243                         break;
244                 case IH_OS_LINUX:
245                         os = "Linux";
246                         break;
247                 case IH_OS_VXWORKS:
248                         os = "VxWorks";
249                         break;
250                 case IH_OS_QNX:
251                         os = "QNX";
252                         break;
253                 case IH_OS_U_BOOT:
254                         os = "U-Boot";
255                         break;
256                 case IH_OS_RTEMS:
257                         os = "RTEMS";
258                         break;
259                 default:
260                         os = "Unknown OS";
261                         break;
262         }
263
264         switch(hdr->ih_arch){
265                 case IH_CPU_INVALID:
266                         arch = "Invalid CPU";
267                         break;
268                 case IH_CPU_ALPHA:
269                         arch = "Alpha";
270                         break;
271                 case IH_CPU_ARM:
272                         arch = "ARM";
273                         break;
274                 case IH_CPU_I386:
275                         arch = "Intel x86";
276                         break;
277                 case IH_CPU_IA64:
278                         arch = "IA64";
279                         break;
280                 case IH_CPU_MIPS:
281                         arch = "MIPS";
282                         break;
283                 case IH_CPU_MIPS64:
284                         arch = "MIPS 64 Bit";
285                         break;
286                 case IH_CPU_PPC:
287                         arch = "PowerPC";
288                         break;
289                 case IH_CPU_S390:
290                         arch = "IBM S390";
291                         break;
292                 case IH_CPU_SH:
293                         arch = "SuperH";
294                         break;
295                 case IH_CPU_SPARC:
296                         arch = "SPARC";
297                         break;
298                 case IH_CPU_SPARC64:
299                         arch = "SPARC 64 Bit";
300                         break;
301                 case IH_CPU_M68K:
302                         arch = "M68K";
303                         break;
304                 case IH_CPU_MICROBLAZE:
305                         arch = "Microblaze";
306                         break;
307                 case IH_CPU_NIOS:
308                         arch = "Nios";
309                         break;
310                 case IH_CPU_NIOS2:
311                         arch = "Nios-II";
312                         break;
313                 default:
314                         arch = "Unknown Architecture";
315                         break;
316         }
317
318         switch(hdr->ih_type){
319                 case IH_TYPE_INVALID:
320                         type = "Invalid Image";
321                         break;
322                 case IH_TYPE_STANDALONE:
323                         type = "Standalone Program";
324                         break;
325                 case IH_TYPE_KERNEL:
326                         type = "Kernel Image";
327                         break;
328                 case IH_TYPE_RAMDISK:
329                         type = "RAMDisk Image";
330                         break;
331                 case IH_TYPE_MULTI:
332                         type = "Multi-File Image";
333                         break;
334                 case IH_TYPE_FIRMWARE:
335                         type = "Firmware";
336                         break;
337                 case IH_TYPE_SCRIPT:
338                         type = "Script";
339                         break;
340                 default:
341                         type = "Unknown Image";
342                         break;
343         }
344
345         switch(hdr->ih_comp){
346                 case IH_COMP_NONE:
347                         comp = "uncompressed";
348                         break;
349                 case IH_COMP_GZIP:
350                         comp = "gzip compressed";
351                         break;
352                 case IH_COMP_BZIP2:
353                         comp = "bzip2 compressed";
354                         break;
355                 case IH_COMP_LZMA:
356                         comp = "lzma compressed";
357                         break;
358                 default:
359                         comp = "unknown compression";
360                         break;
361         }
362
363         printf("%s %s %s (%s)", arch, os, type, comp);
364 }
365
366 void print_image_hdr(image_header_t *hdr){
367 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
368         time_t timestamp = (time_t)ntohl(hdr->ih_time);
369         struct rtc_time tm;
370 #endif
371
372         printf("\n   Image name:   %.*s\n", IH_NMLEN, hdr->ih_name);
373
374 #if (CONFIG_COMMANDS & CFG_CMD_DATE) || defined(CONFIG_TIMESTAMP)
375         to_tm(timestamp, &tm);
376         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);
377 #endif  /* CFG_CMD_DATE, CONFIG_TIMESTAMP */
378
379         puts("   Image type:   ");
380         print_type(hdr);
381
382         printf("\n   Data size:    %d Bytes = ", ntohl(hdr->ih_size));
383         print_size(ntohl(hdr->ih_size), "\n");
384
385         printf("   Load address: 0x%08X\n   Entry point:  0x%08X\n", ntohl(hdr->ih_load), ntohl(hdr->ih_ep));
386
387         if(hdr->ih_type == IH_TYPE_MULTI){
388                 int i;
389                 ulong len;
390                 ulong *len_ptr = (ulong *)((ulong)hdr + sizeof(image_header_t));
391
392                 puts("   Contents:\n");
393
394                 for(i = 0; (len = ntohl(*len_ptr)); ++i, ++len_ptr){
395                         printf("      Image %d: %8ld Bytes = ", i, len);
396                         print_size(len, "\n");
397                 }
398         }
399
400         puts("\n");
401 }
402 #else
403 void print_image_hdr(tplink_image_header_t *hdr){
404         printf("\n   Image name:   %.*s %.*s\n", SIG_LEN, hdr->signiture_1, SIG_LEN_2, hdr->signiture_2);
405           puts("   Image type:   MIPS Linux Kernel Image (lzma compressed)\n");
406         printf("   Data size:    %d Bytes = ", ntohl(hdr->kernelLen));
407         print_size(ntohl(hdr->kernelLen), "\n");
408         printf("   Load address: 0x%08X\n   Entry point:  0x%08X\n\n", ntohl(hdr->kernelTextAddr), ntohl(hdr->kernelEntryPoint));
409 }
410 #endif /* defined(CONFIG_FOR_8DEVICES_CARAMBOLA2) || defined(CONFIG_FOR_DLINK_DIR505_A1) || defined(CONFIG_FOR_DRAGINO_V2) || defined(CONFIG_FOR_MESH_POTATO_V2) || defined(CONFIG_FOR_BSB) */
411
412 #if (CONFIG_COMMANDS & CFG_CMD_BOOTD)
413 int do_bootd(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
414         int rcode = 0;
415 #ifndef CFG_HUSH_PARSER
416         if(run_command (getenv ("bootcmd"), flag) < 0){
417                 rcode = 1;
418         }
419 #else
420         if(parse_string_outer(getenv("bootcmd"), FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0){
421                 rcode = 1;
422         }
423 #endif
424         return(rcode);
425 }
426
427 U_BOOT_CMD(boot, 1, 1, do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);
428
429 /* keep old command name "bootd" for backward compatibility */
430 U_BOOT_CMD(bootd, 1, 1, do_bootd, "boot default, i.e., run 'bootcmd'\n", NULL);
431
432 #endif /* CONFIG_COMMANDS & CFG_CMD_BOOTD */
433
434 #if (CONFIG_COMMANDS & CFG_CMD_IMI)
435 int do_iminfo(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]){
436         ulong addr;
437         int rcode = 0;
438
439         if (argc == 2){
440                 addr = simple_strtoul(argv[1], NULL, 16);
441                 return image_info(addr);
442         } else {
443 #ifdef CFG_LONGHELP
444                 if(cmdtp->help != NULL){
445                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->help);
446                 } else {
447                         printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
448                 }
449 #else
450                 printf("Usage:\n%s %s\n", cmdtp->name, cmdtp->usage);
451 #endif
452                 return(1);
453         }
454
455         return(rcode);
456 }
457
458 static int image_info(ulong addr){
459         ulong data, len, checksum;
460         image_header_t *hdr = &header;
461
462         printf("\nChecking image at 0x%08lX...\n", addr);
463
464         /* Copy header so we can blank CRC field for re-calculation */
465         memmove(&header, (char *)addr, sizeof(image_header_t));
466
467         data = (ulong)&header;
468         len  = sizeof(image_header_t);
469
470         checksum = ntohl(hdr->ih_hcrc);
471         hdr->ih_hcrc = 0;
472
473         if(crc32(0, (uchar *)data, len) != checksum){
474                 puts("## Error: bad header checksum!\n");
475                 return 1;
476         }
477
478         /* for multi-file images we need the data part, too */
479         print_image_hdr((image_header_t *)addr);
480
481         data = addr + sizeof(image_header_t);
482         len  = ntohl(hdr->ih_size);
483
484         puts("   Verifying checksum... ");
485
486         if(crc32(0, (uchar *)data, len) != ntohl(hdr->ih_dcrc)){
487                 puts("bad data CRC!\n");
488                 return(1);
489         }
490
491         puts("OK!\n\n");
492
493         return(0);
494 }
495
496 U_BOOT_CMD(iminfo, 2, 1, do_iminfo, "print firmware header\n", "address\n"
497                 "\t- print header information for firmware image startting at address 'address'\n"
498 );
499
500 #endif  /* CFG_CMD_IMI */