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