* Allow crc32 to be used at address 0x000
[platform/kernel/u-boot.git] / lib_arm / armlinux.c
1 /*
2  * (C) Copyright 2002
3  * Sysgo Real-Time Solutions, GmbH <www.elinos.com>
4  * Marius Groeger <mgroeger@sysgo.de>
5  *
6  * Copyright (C) 2001  Erik Mouw (J.A.K.Mouw@its.tudelft.nl)
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * (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, MA  02111-1307  USA
21  *
22  */
23
24 #include <common.h>
25 #include <command.h>
26 #include <image.h>
27 #include <zlib.h>
28 #include <asm/byteorder.h>
29 #ifdef CONFIG_HAS_DATAFLASH
30 #include <dataflash.h>
31 #endif
32
33 #include <asm/setup.h>
34 #define tag_size(type)  ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
35 #define tag_next(t)     ((struct tag *)((u32 *)(t) + (t)->hdr.size))
36
37 /*cmd_boot.c*/
38 extern int do_reset (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
39
40 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
41     defined (CONFIG_CMDLINE_TAG) || \
42     defined (CONFIG_INITRD_TAG) || \
43     defined (CONFIG_VFD)
44 static void setup_start_tag(bd_t *bd);
45 # ifdef CONFIG_SETUP_MEMORY_TAGS
46 static void setup_memory_tags(bd_t *bd);
47 # endif
48 static void setup_commandline_tag(bd_t *bd, char *commandline);
49 #if 0
50 static void setup_ramdisk_tag(bd_t *bd);
51 #endif
52 # ifdef CONFIG_INITRD_TAG
53 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
54 # endif
55 static void setup_end_tag(bd_t *bd);
56 # if defined (CONFIG_VFD)
57 static void setup_videolfb_tag(gd_t *gd);
58 # endif
59
60
61 static struct tag *params;
62 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
63
64 #ifdef CONFIG_SHOW_BOOT_PROGRESS
65 # include <status_led.h>
66 # define SHOW_BOOT_PROGRESS(arg)        show_boot_progress(arg)
67 #else
68 # define SHOW_BOOT_PROGRESS(arg)
69 #endif
70
71 extern image_header_t header;           /* from cmd_bootm.c */
72
73
74 void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
75                 ulong addr, ulong *len_ptr, int   verify)
76 {
77         DECLARE_GLOBAL_DATA_PTR;
78
79     ulong len = 0, checksum;
80     ulong initrd_start, initrd_end;
81     ulong data;
82     void (*theKernel)(int zero, int arch);
83     image_header_t *hdr = &header;
84     bd_t *bd = gd->bd;
85 #ifdef CONFIG_CMDLINE_TAG
86     char *commandline = getenv("bootargs");
87 #endif
88
89     theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);
90
91     /*
92      * Check if there is an initrd image
93      */
94     if (argc >= 3) {
95         SHOW_BOOT_PROGRESS (9);
96
97         addr = simple_strtoul(argv[2], NULL, 16);
98
99         printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
100
101         /* Copy header so we can blank CRC field for re-calculation */
102 #ifdef CONFIG_HAS_DATAFLASH
103         if (addr_dataflash(addr)){
104                 read_dataflash(addr, sizeof(image_header_t), (char *)&header);
105         } else
106 #endif
107         memcpy (&header, (char *)addr, sizeof(image_header_t));
108
109         if (ntohl(hdr->ih_magic) != IH_MAGIC) {
110             printf ("Bad Magic Number\n");
111             SHOW_BOOT_PROGRESS (-10);
112             do_reset (cmdtp, flag, argc, argv);
113         }
114
115         data = (ulong)&header;
116         len  = sizeof(image_header_t);
117
118         checksum = ntohl(hdr->ih_hcrc);
119         hdr->ih_hcrc = 0;
120
121         if (crc32 (0, (char *)data, len) != checksum) {
122             printf ("Bad Header Checksum\n");
123             SHOW_BOOT_PROGRESS (-11);
124             do_reset (cmdtp, flag, argc, argv);
125         }
126
127         SHOW_BOOT_PROGRESS (10);
128
129         print_image_hdr (hdr);
130
131         data = addr + sizeof(image_header_t);
132         len  = ntohl(hdr->ih_size);
133
134 #ifdef CONFIG_HAS_DATAFLASH
135         if (addr_dataflash(addr)){
136                 read_dataflash(data, len, (char *)CFG_LOAD_ADDR);
137                 data = CFG_LOAD_ADDR;
138         }
139 #endif
140
141         if (verify) {
142             ulong csum = 0;
143
144             printf ("   Verifying Checksum ... ");
145             csum = crc32 (0, (char *)data, len);
146             if (csum != ntohl(hdr->ih_dcrc)) {
147                 printf ("Bad Data CRC\n");
148                 SHOW_BOOT_PROGRESS (-12);
149                 do_reset (cmdtp, flag, argc, argv);
150             }
151             printf ("OK\n");
152         }
153
154         SHOW_BOOT_PROGRESS (11);
155
156         if ((hdr->ih_os   != IH_OS_LINUX)       ||
157             (hdr->ih_arch != IH_CPU_ARM)        ||
158             (hdr->ih_type != IH_TYPE_RAMDISK)   ) {
159             printf ("No Linux ARM Ramdisk Image\n");
160             SHOW_BOOT_PROGRESS (-13);
161             do_reset (cmdtp, flag, argc, argv);
162         }
163
164         /*
165          * Now check if we have a multifile image
166          */
167     } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
168         ulong tail    = ntohl(len_ptr[0]) % 4;
169         int i;
170
171         SHOW_BOOT_PROGRESS (13);
172
173         /* skip kernel length and terminator */
174         data = (ulong)(&len_ptr[2]);
175         /* skip any additional image length fields */
176         for (i=1; len_ptr[i]; ++i)
177           data += 4;
178         /* add kernel length, and align */
179         data += ntohl(len_ptr[0]);
180         if (tail) {
181             data += 4 - tail;
182         }
183
184         len   = ntohl(len_ptr[1]);
185
186     } else {
187         /*
188          * no initrd image
189          */
190         SHOW_BOOT_PROGRESS (14);
191
192         data = 0;
193     }
194
195 #ifdef  DEBUG
196     if (!data) {
197         printf ("No initrd\n");
198     }
199 #endif
200
201     if (data) {
202         initrd_start = data;
203         initrd_end   = initrd_start + len;
204     } else {
205         initrd_start = 0;
206         initrd_end = 0;
207     }
208
209     SHOW_BOOT_PROGRESS (15);
210
211 #ifdef DEBUG
212     printf ("## Transferring control to Linux (at address %08lx) ...\n",
213             (ulong)theKernel);
214 #endif
215
216 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
217     defined (CONFIG_CMDLINE_TAG) || \
218     defined (CONFIG_INITRD_TAG) || \
219     defined (CONFIG_VFD)
220     setup_start_tag(bd);
221 #ifdef CONFIG_SETUP_MEMORY_TAGS
222     setup_memory_tags(bd);
223 #endif
224 #ifdef CONFIG_CMDLINE_TAG
225     setup_commandline_tag(bd, commandline);
226 #endif
227 #ifdef CONFIG_INITRD_TAG
228     setup_initrd_tag(bd, initrd_start, initrd_end);
229 #endif
230 #if 0
231     setup_ramdisk_tag(bd);
232 #endif
233 #if defined (CONFIG_VFD)
234     setup_videolfb_tag((gd_t *)gd);
235 #endif
236     setup_end_tag(bd);
237 #endif
238
239     /* we assume that the kernel is in place */
240     printf("\nStarting kernel ...\n\n");
241
242     cleanup_before_linux();
243
244     theKernel(0, bd->bi_arch_number);
245 }
246
247
248 #if defined (CONFIG_SETUP_MEMORY_TAGS) || \
249     defined (CONFIG_CMDLINE_TAG) || \
250     defined (CONFIG_INITRD_TAG) || \
251     defined (CONFIG_VFD)
252 static void setup_start_tag(bd_t *bd)
253 {
254     params = (struct tag *)bd->bi_boot_params;
255
256     params->hdr.tag = ATAG_CORE;
257     params->hdr.size = tag_size(tag_core);
258
259     params->u.core.flags = 0;
260     params->u.core.pagesize = 0;
261     params->u.core.rootdev = 0;
262
263     params = tag_next(params);
264 }
265
266
267 #ifdef CONFIG_SETUP_MEMORY_TAGS
268 static void setup_memory_tags(bd_t *bd)
269 {
270     int i;
271
272     for(i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
273         params->hdr.tag = ATAG_MEM;
274         params->hdr.size = tag_size(tag_mem32);
275
276         params->u.mem.start = bd->bi_dram[i].start;
277         params->u.mem.size = bd->bi_dram[i].size;
278
279         params = tag_next(params);
280     }
281 }
282 #endif  /* CONFIG_SETUP_MEMORY_TAGS */
283
284
285 static void setup_commandline_tag(bd_t *bd, char *commandline)
286 {
287     char *p;
288
289     /* eat leading white space */
290     for(p = commandline; *p == ' '; p++)
291       ;
292
293     /* skip non-existent command lines so the kernel will still
294      * use its default command line.
295      */
296     if(*p == '\0')
297       return;
298
299     params->hdr.tag = ATAG_CMDLINE;
300     params->hdr.size = (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
301
302     strcpy(params->u.cmdline.cmdline, p);
303
304     params = tag_next(params);
305 }
306
307
308 #ifndef ATAG_INITRD2
309 #define ATAG_INITRD2    0x54420005
310 #endif
311
312 #ifdef CONFIG_INITRD_TAG
313 static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
314 {
315     /* an ATAG_INITRD node tells the kernel where the compressed
316      * ramdisk can be found. ATAG_RDIMG is a better name, actually.
317      */
318     params->hdr.tag = ATAG_INITRD2;
319     params->hdr.size = tag_size(tag_initrd);
320
321     params->u.initrd.start = initrd_start;
322     params->u.initrd.size = initrd_end - initrd_start;
323
324     params = tag_next(params);
325 }
326 #endif  /* CONFIG_INITRD_TAG */
327
328
329 #if 0
330 static void setup_ramdisk_tag(bd_t *bd)
331 {
332     /* an ATAG_RAMDISK node tells the kernel how large the
333      * decompressed ramdisk will become.
334      */
335     params->hdr.tag = ATAG_RAMDISK;
336     params->hdr.size = tag_size(tag_ramdisk);
337
338     params->u.ramdisk.start = 0;
339     /*params->u.ramdisk.size = RAMDISK_SIZE; */
340     params->u.ramdisk.flags = 1;        /* automatically load ramdisk */
341
342     params = tag_next(params);
343 }
344 #endif /* 0 */
345
346 #if defined (CONFIG_VFD)
347 static void setup_videolfb_tag(gd_t *gd)
348 {
349     /* An ATAG_VIDEOLFB node tells the kernel where and how large
350      * the framebuffer for video was allocated (among other things).
351      * Note that a _physical_ address is passed !
352      *
353      * We only use it to pass the address and size, the other entries
354      * in the tag_videolfb are not of interest.
355      */
356     params->hdr.tag = ATAG_VIDEOLFB;
357     params->hdr.size = tag_size(tag_videolfb);
358
359     params->u.videolfb.lfb_base = (u32)gd->fb_base;
360     /* 7168 = 256*4*56/8 - actually 2 pages (8192 bytes) are allocated */
361     params->u.videolfb.lfb_size = 7168;
362
363     params = tag_next(params);
364 }
365 #endif
366
367 static void setup_end_tag(bd_t *bd)
368 {
369     params->hdr.tag = ATAG_NONE;
370     params->hdr.size = 0;
371 }
372
373 #endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */