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>.
6 * Currently maintained by: Tom Rini <trini@kernel.crashing.org>
9 #include <linux/config.h>
10 #include <linux/types.h>
11 #include <linux/string.h>
12 #include <asm/bootinfo.h>
15 #include <asm/residual.h>
16 #if defined(CONFIG_4xx)
17 #include <asm/ibm4xx.h>
18 #elif defined(CONFIG_8xx)
19 #include <asm/mpc8xx.h>
20 #elif defined(CONFIG_8260)
21 #include <asm/mpc8260.h>
27 /* The linker tells us where the image is. */
28 extern char __image_begin, __image_end;
29 extern char __ramdisk_begin, __ramdisk_end;
32 /* Because of the limited amount of memory on embedded, it presents
33 * loading problems. The biggest is that we load this boot program
34 * into a relatively low memory address, and the Linux kernel Bss often
35 * extends into this space when it get loaded. When the kernel starts
36 * and zeros the BSS space, it also writes over the information we
37 * save here and pass to the kernel (usually board info).
38 * On these boards, we grab some known memory holes to hold this information.
41 char *cmd_line = cmd_buf;
46 /* This is for 4xx treeboot. It provides a place for the bootrom
47 * give us a pointer to a rom environment command line.
49 char *bootrom_cmdline = "";
51 /* This is the default cmdline that will be given to the user at boot time..
52 * If none was specified at compile time, we'll give it one that should work.
54 #ifdef CONFIG_CMDLINE_BOOL
55 char compiled_string[] = CONFIG_CMDLINE;
57 char ramroot_string[] = "root=/dev/ram";
58 char netroot_string[] = "root=/dev/nfs rw ip=on";
60 /* Serial port to use. */
61 unsigned long com_port;
63 /* We need to make sure that this is before the images to ensure
64 * that it's in a mapped location. - Tom */
65 bd_t hold_resid_buf __attribute__ ((__section__ (".data.boot")));
66 bd_t *hold_residual = &hold_resid_buf;
68 extern unsigned long serial_init(int chan, bd_t *bp);
69 extern void serial_close(unsigned long com_port);
70 extern unsigned long start;
71 extern void flush_instruction_cache(void);
72 extern void gunzip(void *, int, unsigned char *, int *);
73 extern void embed_config(bd_t **bp);
76 load_kernel(unsigned long load_addr, int num_words, unsigned long cksum, bd_t *bp)
79 int timer = 0, zimage_size;
80 unsigned long initrd_size;
82 /* First, capture the embedded board information. Then
83 * initialize the serial console port.
86 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
87 com_port = serial_init(0, bp);
90 /* Grab some space for the command line and board info. Since
91 * we no longer use the ELF header, but it was loaded, grab
95 /* Because of the way the MBX loads the ELF image, we can't
96 * tell where we started. We read a magic variable from the NVRAM
97 * that gives us the intermediate buffer load address.
99 load_addr = *(uint *)0xfa000020;
100 load_addr += 0x10000; /* Skip ELF header */
102 /* copy board data */
104 memcpy(hold_residual,bp,sizeof(bd_t));
106 /* Set end of memory available to us. It is always the highest
107 * memory address provided by the board information.
109 end_avail = (char *)(bp->bi_memsize);
111 puts("\nloaded at: "); puthex(load_addr);
112 puts(" "); puthex((unsigned long)(load_addr + (4*num_words))); puts("\n");
113 if ( (unsigned long)load_addr != (unsigned long)&start ) {
114 puts("relocated to: "); puthex((unsigned long)&start);
116 puthex((unsigned long)((unsigned long)&start + (4*num_words)));
121 puts("board data at: "); puthex((unsigned long)bp);
123 puthex((unsigned long)((unsigned long)bp + sizeof(bd_t)));
124 puts("\nrelocated to: ");
125 puthex((unsigned long)hold_residual);
127 puthex((unsigned long)((unsigned long)hold_residual + sizeof(bd_t)));
132 * We link ourself to an arbitrary low address. When we run, we
133 * relocate outself to that address. __image_being points to
134 * the part of the image where the zImage is. -- Tom
136 zimage_start = (char *)(unsigned long)(&__image_begin);
137 zimage_size = (unsigned long)(&__image_end) -
138 (unsigned long)(&__image_begin);
140 initrd_size = (unsigned long)(&__ramdisk_end) -
141 (unsigned long)(&__ramdisk_begin);
144 * The zImage and initrd will be between start and _end, so they've
145 * already been moved once. We're good to go now. -- Tom
147 puts("zimage at: "); puthex((unsigned long)zimage_start);
148 puts(" "); puthex((unsigned long)(zimage_size+zimage_start));
153 puthex((unsigned long)(&__ramdisk_begin));
154 puts(" "); puthex((unsigned long)(&__ramdisk_end));puts("\n");
158 * setup avail_ram - this is the first part of ram usable
159 * by the uncompress code. Anything after this program in RAM
160 * is now fair game. -- Tom
162 avail_ram = (char *)PAGE_ALIGN((unsigned long)_end);
164 puts("avail ram: "); puthex((unsigned long)avail_ram); puts(" ");
165 puthex((unsigned long)end_avail); puts("\n");
166 puts("\nLinux/PPC load: ");
168 /* This is where we try and pick the right command line for booting.
169 * If we were given one at compile time, use it. It Is Right.
170 * If we weren't, see if we have a ramdisk. If so, thats root.
171 * When in doubt, give them the netroot (root=/dev/nfs rw) -- Tom
173 #ifdef CONFIG_CMDLINE_BOOL
174 memcpy (cmd_line, compiled_string, sizeof(compiled_string));
177 memcpy (cmd_line, ramroot_string, sizeof(ramroot_string));
179 memcpy (cmd_line, netroot_string, sizeof(netroot_string));
183 while (timer++ < 5*1000) {
185 while ((ch = getc()) != '\n' && ch != '\r') {
186 if (ch == '\b' || ch == '\177') {
187 if (cp != cmd_line) {
191 } else if (ch == '\030' /* ^x */
192 || ch == '\025') { /* ^u */
193 while (cp != cmd_line) {
202 break; /* Exit 'timer' loop */
204 udelay(1000); /* 1 msec */
207 puts("\nUncompressing Linux...");
209 gunzip(0, 0x400000, zimage_start, &zimage_size);
210 flush_instruction_cache();
213 struct bi_record *rec;
214 unsigned long initrd_loc;
215 unsigned long rec_loc = _ALIGN((unsigned long)(zimage_size) +
216 (1 << 20) - 1, (1 << 20));
217 rec = (struct bi_record *)rec_loc;
219 /* We need to make sure that the initrd and bi_recs do not
222 initrd_loc = (unsigned long)(&__ramdisk_begin);
223 /* If the bi_recs are in the middle of the current
224 * initrd, move the initrd to the next MB
226 if ((rec_loc > initrd_loc) &&
227 ((initrd_loc + initrd_size)
229 initrd_loc = _ALIGN((unsigned long)(zimage_size)
230 + (2 << 20) - 1, (2 << 20));
231 memmove((void *)initrd_loc, &__ramdisk_begin,
233 puts("initrd moved: "); puthex(initrd_loc);
234 puts(" "); puthex(initrd_loc + initrd_size);
240 rec->size = sizeof(struct bi_record);
241 rec = (struct bi_record *)((unsigned long)rec + rec->size);
243 rec->tag = BI_CMD_LINE;
244 memcpy( (char *)rec->data, cmd_line, strlen(cmd_line)+1);
245 rec->size = sizeof(struct bi_record) + strlen(cmd_line) + 1;
246 rec = (struct bi_record *)((unsigned long)rec + rec->size);
249 rec->tag = BI_INITRD;
250 rec->data[0] = initrd_loc;
251 rec->data[1] = initrd_size;
252 rec->size = sizeof(struct bi_record) + 2 *
253 sizeof(unsigned long);
254 rec = (struct bi_record *)((unsigned long)rec +
259 rec->size = sizeof(struct bi_record);
260 rec = (struct bi_record *)((unsigned long)rec + rec->size);
262 puts("Now booting the kernel\n");
263 #if defined(CONFIG_SERIAL_CPM_CONSOLE) || defined(CONFIG_SERIAL_8250_CONSOLE)
264 serial_close(com_port);
267 return (unsigned long)hold_residual;