blob: 10219eeca054c22f24b1693c14de80f035ec8349 [file] [log] [blame]
Linus Torvalds1da177e2005-04-16 15:20:36 -07001/*
2 * Originally adapted by Gary Thomas. Much additional work by
3 * Cort Dougan <cort@fsmlabs.com>. On top of that still more work by
4 * Dan Malek <dmalek@jlc.net>.
5 *
6 * Currently maintained by: Tom Rini <trini@kernel.crashing.org>
7 */
8
Linus Torvalds1da177e2005-04-16 15:20:36 -07009#include <linux/types.h>
10#include <linux/string.h>
11#include <asm/bootinfo.h>
12#include <asm/mmu.h>
13#include <asm/page.h>
14#include <asm/residual.h>
15#if defined(CONFIG_4xx)
16#include <asm/ibm4xx.h>
17#elif defined(CONFIG_8xx)
18#include <asm/mpc8xx.h>
19#elif defined(CONFIG_8260)
20#include <asm/mpc8260.h>
21#endif
22
23#include "nonstdio.h"
24
25/* The linker tells us where the image is. */
26extern char __image_begin, __image_end;
27extern char __ramdisk_begin, __ramdisk_end;
28extern char _end[];
29
30/* Because of the limited amount of memory on embedded, it presents
31 * loading problems. The biggest is that we load this boot program
32 * into a relatively low memory address, and the Linux kernel Bss often
33 * extends into this space when it get loaded. When the kernel starts
34 * and zeros the BSS space, it also writes over the information we
35 * save here and pass to the kernel (usually board info).
36 * On these boards, we grab some known memory holes to hold this information.
37 */
38char cmd_buf[256];
39char *cmd_line = cmd_buf;
40char *avail_ram;
41char *end_avail;
42char *zimage_start;
43
44/* This is for 4xx treeboot. It provides a place for the bootrom
45 * give us a pointer to a rom environment command line.
46 */
47char *bootrom_cmdline = "";
48
49/* This is the default cmdline that will be given to the user at boot time..
50 * If none was specified at compile time, we'll give it one that should work.
51 * -- Tom */
52#ifdef CONFIG_CMDLINE_BOOL
53char compiled_string[] = CONFIG_CMDLINE;
54#endif
55char ramroot_string[] = "root=/dev/ram";
56char netroot_string[] = "root=/dev/nfs rw ip=on";
57
58/* Serial port to use. */
59unsigned long com_port;
60
61/* We need to make sure that this is before the images to ensure
62 * that it's in a mapped location. - Tom */
63bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
64bd_t *hold_residual = &hold_resid_buf;
65
66extern unsigned long serial_init(int chan, bd_t *bp);
67extern void serial_close(unsigned long com_port);
68extern unsigned long start;
69extern void flush_instruction_cache(void);
70extern void gunzip(void *, int, unsigned char *, int *);
71extern void embed_config(bd_t **bp);
72
73/* Weak function for boards which don't need to build the
74 * board info struct because they are using PPCBoot/U-Boot.
75 */
76void __attribute__ ((weak))
77embed_config(bd_t **bdp)
78{
79}
80
81unsigned long
82load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
83{
84 char *cp, ch;
85 int timer = 0, zimage_size;
86 unsigned long initrd_size;
87
88 /* First, capture the embedded board information. Then
89 * initialize the serial console port.
90 */
91 embed_config(&bp);
92#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
93 com_port = serial_init(0, bp);
94#endif
95
96 /* Grab some space for the command line and board info. Since
97 * we no longer use the ELF header, but it was loaded, grab
98 * that space.
99 */
100#ifdef CONFIG_MBX
101 /* Because of the way the MBX loads the ELF image, we can't
102 * tell where we started. We read a magic variable from the NVRAM
103 * that gives us the intermediate buffer load address.
104 */
105 load_addr = *(uint *)0xfa000020;
106 load_addr += 0x10000; /* Skip ELF header */
107#endif
108 /* copy board data */
109 if (bp)
110 memcpy(hold_residual,bp,sizeof(bd_t));
111
112 /* Set end of memory available to us. It is always the highest
113 * memory address provided by the board information.
114 */
115 end_avail = (char *)(bp->bi_memsize);
116
117 puts("\nloaded at: "); puthex(load_addr);
118 puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
119 if ( (unsigned long)load_addr != (unsigned long)&start ) {
120 puts("relocated to: "); puthex((unsigned long)&start);
121 puts(" ");
122 puthex((unsigned long)((unsigned long)&start + (4*num_words)));
123 puts("\n");
124 }
125
126 if ( bp ) {
127 puts("board data at: "); puthex((unsigned long)bp);
128 puts(" ");
129 puthex((unsigned long)((unsigned long)bp + sizeof(bd_t)));
130 puts("\nrelocated to: ");
131 puthex((unsigned long)hold_residual);
132 puts(" ");
133 puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
134 puts("\n");
135 }
136
137 /*
138 * We link ourself to an arbitrary low address. When we run, we
139 * relocate outself to that address. __image_being points to
140 * the part of the image where the zImage is. -- Tom
141 */
142 zimage_start = (char *)(unsigned long)(&__image_begin);
143 zimage_size = (unsigned long)(&__image_end) -
144 (unsigned long)(&__image_begin);
145
146 initrd_size = (unsigned long)(&__ramdisk_end) -
147 (unsigned long)(&__ramdisk_begin);
148
149 /*
150 * The zImage and initrd will be between start and _end, so they've
151 * already been moved once. We're good to go now. -- Tom
152 */
153 puts("zimage at: "); puthex((unsigned long)zimage_start);
154 puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
155 puts("\n");
156
157 if ( initrd_size ) {
158 puts("initrd at: ");
159 puthex((unsigned long)(&__ramdisk_begin));
160 puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
161 }
162
163 /*
164 * setup avail_ram - this is the first part of ram usable
165 * by the uncompress code. Anything after this program in RAM
166 * is now fair game. -- Tom
167 */
168 avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
169
170 puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
171 puthex((unsigned long)end_avail); puts("\n");
172 puts("\nLinux/PPC load: ");
173 cp = cmd_line;
174 /* This is where we try and pick the right command line for booting.
175 * If we were given one at compile time, use it. It Is Right.
176 * If we weren't, see if we have a ramdisk. If so, thats root.
177 * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom
178 */
179#ifdef CONFIG_CMDLINE_BOOL
180 memcpy (cmd_line, compiled_string, sizeof(compiled_string));
181#else
182 if ( initrd_size )
183 memcpy (cmd_line, ramroot_string, sizeof(ramroot_string));
184 else
185 memcpy (cmd_line, netroot_string, sizeof(netroot_string));
186#endif
187 while ( *cp )
188 putc(*cp++);
189 while (timer++ < 5*1000) {
190 if (tstc()) {
191 while ((ch = getc()) != '\n' && ch != '\r') {
192 if (ch == '\b' || ch == '\177') {
193 if (cp != cmd_line) {
194 cp--;
195 puts("\b \b");
196 }
197 } else if (ch == '\030' /* ^x */
198 || ch == '\025') { /* ^u */
199 while (cp != cmd_line) {
200 cp--;
201 puts("\b \b");
202 }
203 } else {
204 *cp++ = ch;
205 putc(ch);
206 }
207 }
208 break; /* Exit 'timer' loop */
209 }
210 udelay(1000); /* 1 msec */
211 }
212 *cp = 0;
213 puts("\nUncompressing Linux...");
214
215 gunzip(0, 0x400000, zimage_start, &zimage_size);
216 flush_instruction_cache();
217 puts("done.\n");
218 {
219 struct bi_record *rec;
220 unsigned long initrd_loc = 0;
221 unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
222 (1 << 20) - 1, (1 << 20));
223 rec = (struct bi_record *)rec_loc;
224
225 /* We need to make sure that the initrd and bi_recs do not
226 * overlap. */
227 if ( initrd_size ) {
228 initrd_loc = (unsigned long)(&__ramdisk_begin);
229 /* If the bi_recs are in the middle of the current
230 * initrd, move the initrd to the next MB
231 * boundary. */
232 if ((rec_loc > initrd_loc) &&
233 ((initrd_loc + initrd_size)
234 > rec_loc)) {
235 initrd_loc = _ALIGN((unsigned long)(zimage_size)
236 + (2 << 20) - 1, (2 << 20));
237 memmove((void *)initrd_loc, &__ramdisk_begin,
238 initrd_size);
239 puts("initrd moved: "); puthex(initrd_loc);
240 puts(" "); puthex(initrd_loc + initrd_size);
241 puts("\n");
242 }
243 }
244
245 rec->tag = BI_FIRST;
246 rec->size = sizeof(struct bi_record);
247 rec = (struct bi_record *)((unsigned long)rec + rec->size);
248
249 rec->tag = BI_CMD_LINE;
250 memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
251 rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
252 rec = (struct bi_record *)((unsigned long)rec + rec->size);
253
254 if ( initrd_size ) {
255 rec->tag = BI_INITRD;
256 rec->data[0] = initrd_loc;
257 rec->data[1] = initrd_size;
258 rec->size = sizeof(struct bi_record) + 2 *
259 sizeof(unsigned long);
260 rec = (struct bi_record *)((unsigned long)rec +
261 rec->size);
262 }
263
264 rec->tag = BI_LAST;
265 rec->size = sizeof(struct bi_record);
266 rec = (struct bi_record *)((unsigned long)rec + rec->size);
267 }
268 puts("Now booting the kernel\n");
269#if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
270 serial_close(com_port);
271#endif
272
273 return (unsigned long)hold_residual;
274}