blob: 33f86e9ffe9eba6754124f00c73dfa0921b1e28a [file] [log] [blame]
wdenkc6097192002-11-03 00:24:07 +00001/*
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 <cmd_boot.h>
27#include <image.h>
28#include <zlib.h>
29#include <asm/byteorder.h>
30
31#include <asm/setup.h>
32#define tag_size(type) ((sizeof(struct tag_header) + sizeof(struct type)) >> 2)
33#define tag_next(t) ((struct tag *)((u32 *)(t) + (t)->hdr.size))
34
35#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
36 defined (CONFIG_CMDLINE_TAG) || \
37 defined (CONFIG_INITRD_TAG) || \
38 defined (CONFIG_VFD)
39static void setup_start_tag(bd_t *bd);
wdenk699b13a2002-11-03 18:03:52 +000040# ifdef CONFIG_SETUP_MEMORY_TAGS
wdenkc6097192002-11-03 00:24:07 +000041static void setup_memory_tags(bd_t *bd);
wdenk699b13a2002-11-03 18:03:52 +000042# endif
wdenkc6097192002-11-03 00:24:07 +000043static void setup_commandline_tag(bd_t *bd, char *commandline);
44#if 0
45static void setup_ramdisk_tag(bd_t *bd);
46#endif
wdenk699b13a2002-11-03 18:03:52 +000047# ifdef CONFIG_INITRD_TAG
wdenkc6097192002-11-03 00:24:07 +000048static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end);
wdenk699b13a2002-11-03 18:03:52 +000049# endif
wdenkc6097192002-11-03 00:24:07 +000050static void setup_end_tag(bd_t *bd);
wdenk699b13a2002-11-03 18:03:52 +000051# if defined (CONFIG_VFD)
wdenkc6097192002-11-03 00:24:07 +000052static void setup_videolfb_tag(gd_t *gd);
wdenk699b13a2002-11-03 18:03:52 +000053# endif
wdenkc6097192002-11-03 00:24:07 +000054
55
56static struct tag *params;
57#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */
58
59extern image_header_t header; /* from cmd_bootm.c */
60
61
62void do_bootm_linux(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[],
63 ulong addr, ulong *len_ptr, int verify)
64{
65 DECLARE_GLOBAL_DATA_PTR;
66
67 ulong len = 0, checksum;
68 ulong initrd_start, initrd_end;
69 ulong data;
70 void (*theKernel)(int zero, int arch);
71 image_header_t *hdr = &header;
72 bd_t *bd = gd->bd;
73#ifdef CONFIG_CMDLINE_TAG
74 char *commandline = getenv("bootargs");
75#endif
76
77 theKernel = (void (*)(int, int))ntohl(hdr->ih_ep);
78
79 /*
80 * Check if there is an initrd image
81 */
82 if (argc >= 3) {
83 addr = simple_strtoul(argv[2], NULL, 16);
84
85 printf ("## Loading Ramdisk Image at %08lx ...\n", addr);
86
87 /* Copy header so we can blank CRC field for re-calculation */
88 memcpy (&header, (char *)addr, sizeof(image_header_t));
89
90 if (ntohl(hdr->ih_magic) != IH_MAGIC) {
91 printf ("Bad Magic Number\n");
92 do_reset (cmdtp, flag, argc, argv);
93 }
94
95 data = (ulong)&header;
96 len = sizeof(image_header_t);
97
98 checksum = ntohl(hdr->ih_hcrc);
99 hdr->ih_hcrc = 0;
100
101 if (crc32 (0, (char *)data, len) != checksum) {
102 printf ("Bad Header Checksum\n");
103 do_reset (cmdtp, flag, argc, argv);
104 }
105
106 print_image_hdr (hdr);
107
108 data = addr + sizeof(image_header_t);
109 len = ntohl(hdr->ih_size);
110
111 if (verify) {
112 ulong csum = 0;
113
114 printf (" Verifying Checksum ... ");
115 csum = crc32 (0, (char *)data, len);
116 if (csum != ntohl(hdr->ih_dcrc)) {
117 printf ("Bad Data CRC\n");
118 do_reset (cmdtp, flag, argc, argv);
119 }
120 printf ("OK\n");
121 }
122
123 if ((hdr->ih_os != IH_OS_LINUX) ||
124 (hdr->ih_arch != IH_CPU_ARM) ||
125 (hdr->ih_type != IH_TYPE_RAMDISK) ) {
126 printf ("No Linux ARM Ramdisk Image\n");
127 do_reset (cmdtp, flag, argc, argv);
128 }
129
130 /*
131 * Now check if we have a multifile image
132 */
133 } else if ((hdr->ih_type==IH_TYPE_MULTI) && (len_ptr[1])) {
134 ulong tail = ntohl(len_ptr[0]) % 4;
135 int i;
136
137 /* skip kernel length and terminator */
138 data = (ulong)(&len_ptr[2]);
139 /* skip any additional image length fields */
140 for (i=1; len_ptr[i]; ++i)
141 data += 4;
142 /* add kernel length, and align */
143 data += ntohl(len_ptr[0]);
144 if (tail) {
145 data += 4 - tail;
146 }
147
148 len = ntohl(len_ptr[1]);
149
150 } else {
151 /*
152 * no initrd image
153 */
154 data = 0;
155 }
156
157#ifdef DEBUG
158 if (!data) {
159 printf ("No initrd\n");
160 }
161#endif
162
163 if (data) {
164 initrd_start = data;
165 initrd_end = initrd_start + len;
166 } else {
167 initrd_start = 0;
168 initrd_end = 0;
169 }
170
171#ifdef DEBUG
172 printf ("## Transferring control to Linux (at address %08lx) ...\n",
173 (ulong)theKernel);
174#endif
175
176#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
177 defined (CONFIG_CMDLINE_TAG) || \
178 defined (CONFIG_INITRD_TAG) || \
179 defined (CONFIG_VFD)
180 setup_start_tag(bd);
181#ifdef CONFIG_SETUP_MEMORY_TAGS
182 setup_memory_tags(bd);
183#endif
184#ifdef CONFIG_CMDLINE_TAG
185 setup_commandline_tag(bd, commandline);
186#endif
187#ifdef CONFIG_INITRD_TAG
188 setup_initrd_tag(bd, initrd_start, initrd_end);
189#endif
190#if 0
191 setup_ramdisk_tag(bd);
192#endif
193#if defined (CONFIG_VFD)
194 setup_videolfb_tag(gd);
195#endif
196 setup_end_tag(bd);
197#endif
198
199 /* we assume that the kernel is in place */
200 printf("\nStarting kernel ...\n\n");
201
202 cleanup_before_linux();
203
204 theKernel(0, bd->bi_arch_number);
205}
206
207
208#if defined (CONFIG_SETUP_MEMORY_TAGS) || \
209 defined (CONFIG_CMDLINE_TAG) || \
210 defined (CONFIG_INITRD_TAG) || \
211 defined (CONFIG_VFD)
212static void setup_start_tag(bd_t *bd)
213{
214 params = (struct tag *)bd->bi_boot_params;
215
216 params->hdr.tag = ATAG_CORE;
217 params->hdr.size = tag_size(tag_core);
218
219 params->u.core.flags = 0;
220 params->u.core.pagesize = 0;
221 params->u.core.rootdev = 0;
222
223 params = tag_next(params);
224}
225
226
wdenk699b13a2002-11-03 18:03:52 +0000227#ifdef CONFIG_SETUP_MEMORY_TAGS
wdenkc6097192002-11-03 00:24:07 +0000228static void setup_memory_tags(bd_t *bd)
229{
230 int i;
231
232 for(i = 0; i < CONFIG_NR_DRAM_BANKS; i++) {
233 params->hdr.tag = ATAG_MEM;
234 params->hdr.size = tag_size(tag_mem32);
235
236 params->u.mem.start = bd->bi_dram[i].start;
237 params->u.mem.size = bd->bi_dram[i].size;
238
239 params = tag_next(params);
240 }
241}
wdenk699b13a2002-11-03 18:03:52 +0000242#endif /* CONFIG_SETUP_MEMORY_TAGS */
wdenkc6097192002-11-03 00:24:07 +0000243
244
245static void setup_commandline_tag(bd_t *bd, char *commandline)
246{
247 char *p;
248
249 /* eat leading white space */
250 for(p = commandline; *p == ' '; p++)
251 ;
252
253 /* skip non-existent command lines so the kernel will still
254 * use its default command line.
255 */
256 if(*p == '\0')
257 return;
258
259 params->hdr.tag = ATAG_CMDLINE;
260 params->hdr.size = (sizeof(struct tag_header) + strlen(p) + 1 + 4) >> 2;
261
262 strcpy(params->u.cmdline.cmdline, p);
263
264 params = tag_next(params);
265}
266
267
268#ifndef ATAG_INITRD2
269#define ATAG_INITRD2 0x54420005
270#endif
wdenk699b13a2002-11-03 18:03:52 +0000271
272#ifdef CONFIG_INITRD_TAG
wdenkc6097192002-11-03 00:24:07 +0000273static void setup_initrd_tag(bd_t *bd, ulong initrd_start, ulong initrd_end)
274{
275 /* an ATAG_INITRD node tells the kernel where the compressed
276 * ramdisk can be found. ATAG_RDIMG is a better name, actually.
277 */
278 params->hdr.tag = ATAG_INITRD2;
279 params->hdr.size = tag_size(tag_initrd);
280
281 params->u.initrd.start = initrd_start;
282 params->u.initrd.size = initrd_end - initrd_start;
283
284 params = tag_next(params);
285}
wdenk699b13a2002-11-03 18:03:52 +0000286#endif /* CONFIG_INITRD_TAG */
wdenkc6097192002-11-03 00:24:07 +0000287
288
289#if 0
290static void setup_ramdisk_tag(bd_t *bd)
291{
292 /* an ATAG_RAMDISK node tells the kernel how large the
293 * decompressed ramdisk will become.
294 */
295 params->hdr.tag = ATAG_RAMDISK;
296 params->hdr.size = tag_size(tag_ramdisk);
297
298 params->u.ramdisk.start = 0;
299 /*params->u.ramdisk.size = RAMDISK_SIZE; */
300 params->u.ramdisk.flags = 1; /* automatically load ramdisk */
301
302 params = tag_next(params);
303}
304#endif /* 0 */
305
306#if defined (CONFIG_VFD)
307static void setup_videolfb_tag(gd_t *gd)
308{
309 /* An ATAG_VIDEOLFB node tells the kernel where and how large
310 * the framebuffer for video was allocated (among other things).
311 * Note that a _physical_ address is passed !
312 *
313 * We only use it to pass the address and size, the other entries
314 * in the tag_videolfb are not of interest.
315 */
316 params->hdr.tag = ATAG_VIDEOLFB;
317 params->hdr.size = tag_size(tag_videolfb);
318
319 params->u.videolfb.lfb_base = (u32)gd->fb_base;
320 /* 7168 = 256*4*56/8 - actually 2 pages (8192 bytes) are allocated */
321 params->u.videolfb.lfb_size = 7168;
322
323 params = tag_next(params);
324}
325#endif
326
327static void setup_end_tag(bd_t *bd)
328{
329 params->hdr.tag = ATAG_NONE;
330 params->hdr.size = 0;
331}
332
333#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */